diff --git a/custom/dependencies/hidapi/.github/workflows/builds.yml b/custom/dependencies/hidapi/.github/workflows/builds.yml
index 72d1c3358..f1bd56c69 100644
--- a/custom/dependencies/hidapi/.github/workflows/builds.yml
+++ b/custom/dependencies/hidapi/.github/workflows/builds.yml
@@ -47,7 +47,10 @@ jobs:
- name: Check artifacts
uses: andstor/file-existence-action@v1
with:
- files: "install/shared/lib/libhidapi.dylib, install/shared/include/hidapi/hidapi.h, install/framework/lib/hidapi.framework/hidapi, install/framework/lib/hidapi.framework/Headers/hidapi.h"
+ files: "install/shared/lib/libhidapi.dylib, \
+ install/shared/include/hidapi/hidapi.h, \
+ install/framework/lib/hidapi.framework/hidapi, \
+ install/framework/lib/hidapi.framework/Headers/hidapi.h"
allow_failure: true
ubuntu-cmake:
@@ -59,7 +62,9 @@ jobs:
with:
path: hidapisrc
- name: Install dependencies
- run: sudo apt install libudev-dev libusb-1.0-0-dev
+ run: |
+ sudo apt update
+ sudo apt install libudev-dev libusb-1.0-0-dev
- name: Configure CMake
run: |
rm -rf build install
@@ -74,7 +79,14 @@ jobs:
- name: Check artifacts
uses: andstor/file-existence-action@v1
with:
- files: "install/shared/lib/libhidapi-libusb.so, install/shared/lib/libhidapi-hidraw.so, install/shared/include/hidapi/hidapi.h, install/static/lib/libhidapi-libusb.a, install/static/lib/libhidapi-hidraw.a, install/static/include/hidapi/hidapi.h"
+ files: "install/shared/lib/libhidapi-libusb.so, \
+ install/shared/lib/libhidapi-hidraw.so, \
+ install/shared/include/hidapi/hidapi.h, \
+ install/shared/include/hidapi/hidapi_libusb.h, \
+ install/static/lib/libhidapi-libusb.a, \
+ install/static/lib/libhidapi-hidraw.a, \
+ install/static/include/hidapi/hidapi.h, \
+ install/static/include/hidapi/hidapi_libusb.h"
allow_failure: true
windows-cmake-msvc:
diff --git a/custom/dependencies/hidapi/.gitignore b/custom/dependencies/hidapi/.gitignore
index 9963751f3..24c4c2e51 100644
--- a/custom/dependencies/hidapi/.gitignore
+++ b/custom/dependencies/hidapi/.gitignore
@@ -21,4 +21,8 @@ Makefile
stamp-h1
libtool
+# macOS
.DS_Store
+
+# Qt Creator
+CMakeLists.txt.user
diff --git a/custom/dependencies/hidapi/.gitrepo b/custom/dependencies/hidapi/.gitrepo
index 5d64ed0e9..023fc09b8 100644
--- a/custom/dependencies/hidapi/.gitrepo
+++ b/custom/dependencies/hidapi/.gitrepo
@@ -6,7 +6,7 @@
[subrepo]
remote = https://github.com/libusb/hidapi.git
branch = master
- commit = 382138ee67adf539f60fc986a3409cf1f1fc3cee
- parent = b0b794fdc973191c6e3c46cc1cd0adb45f81d033
+ commit = b66d7c2c889d39cdce8eedc50692c318911b04a9
+ parent = 9ede812a19ae69de06ec4d0fb5227b67c1b0327c
method = merge
cmdver = 0.4.3
diff --git a/custom/dependencies/hidapi/AUTHORS.txt b/custom/dependencies/hidapi/AUTHORS.txt
index e08cb1619..7193d71e0 100644
--- a/custom/dependencies/hidapi/AUTHORS.txt
+++ b/custom/dependencies/hidapi/AUTHORS.txt
@@ -14,5 +14,5 @@ libusb/hidapi Team:
Development/maintainance since June 4th 2019
For a comprehensive list of contributions, see the commit list at github:
- https://github.com/libusb/hidapi/commits/master
+ https://github.com/libusb/hidapi/graphs/contributors
diff --git a/custom/dependencies/hidapi/BUILD.autotools.md b/custom/dependencies/hidapi/BUILD.autotools.md
index 1bac2bbaf..24b20a5af 100644
--- a/custom/dependencies/hidapi/BUILD.autotools.md
+++ b/custom/dependencies/hidapi/BUILD.autotools.md
@@ -1,4 +1,12 @@
-# Building HIDAPI using Autotools
+# Building HIDAPI using Autotools (deprecated)
+
+---
+**NOTE**: for all intentions and purposes the Autotools build scripts for HIDAPI are _deprecated_ and going to be obsolete in the future.
+HIDAPI Team recommends using CMake build for HIDAPI.
+If you are already using Autotools build scripts provided by HIDAPI,
+consider switching to CMake build scripts as soon as possible.
+
+---
To be able to use Autotools to build HIDAPI, it has to be [installed](#installing-autotools)/available in the system.
diff --git a/custom/dependencies/hidapi/BUILD.cmake.md b/custom/dependencies/hidapi/BUILD.cmake.md
index c40f89396..364c815e3 100644
--- a/custom/dependencies/hidapi/BUILD.cmake.md
+++ b/custom/dependencies/hidapi/BUILD.cmake.md
@@ -179,6 +179,12 @@ set(BUILD_SHARED_LIBS FALSE) # HIDAPI as static library on all platforms
add_subdirectory(hidapi)
```
+
+ NOTE
+
+ If you project happen to use `BUILD_SHARED_LIBS` as a `CACHE` variable globally for you project, setting it as simple variable, as showed above _will have not affect_ up until _CMake 3.13_. See [CMP0077](https://cmake.org/cmake/help/latest/policy/CMP0077.html) for details.
+
+
There are several important differences in the behavior of HIDAPI CMake build system when CMake is built as standalone package vs subdirectory build:
1) In _standalone build_ a number of standard and HIDAPI-specific variables are marked as _cache variables_ or _options_.
diff --git a/custom/dependencies/hidapi/BUILD.md b/custom/dependencies/hidapi/BUILD.md
index 51abc656c..b78e82fe4 100644
--- a/custom/dependencies/hidapi/BUILD.md
+++ b/custom/dependencies/hidapi/BUILD.md
@@ -17,12 +17,14 @@
For various reasons you may need to build HIDAPI on your own.
It can be done in several different ways:
-- using [Autotools](BUILD.autotools.md);
- using [CMake](BUILD.cmake.md);
+- using [Autotools](BUILD.autotools.md) (deprecated);
- using [manual makefiles](#building-the-manual-way-on-unix-platforms).
**Autotools** build system is historically first mature build system for
-HIDAPI. Most common usage of it is in its separate README: [BUILD.autotools.md](BUILD.autotools.md).
+HIDAPI. Most common usage of it is in its separate README: [BUILD.autotools.md](BUILD.autotools.md).
+NOTE: for all intentions and purposes the Autotools build scripts for HIDAPI are _deprecated_ and going to be obsolete in the future.
+HIDAPI Team recommends using CMake build for HIDAPI.
**CMake** build system is de facto an industry standard for many open-source and proprietary projects and solutions.
HIDAPI is one of the projects which uses the power of CMake for its advantage.
@@ -104,19 +106,5 @@ To build HIDAPI using MinGW or Cygwin using Autotools, use a general Autotools
Any windows builds (MSVC or MinGW/Cygwin) are also supported by [CMake](BUILD.cmake.md).
-HIDAPI can also be built using the Windows DDK (now also called the Windows
-Driver Kit or WDK). This method was originally required for the HIDAPI build
-but not anymore. However, some users still prefer this method. It is not as
-well supported anymore but should still work. Patches are welcome if it does
-not. To build using the DDK:
-
- 1. Install the Windows Driver Kit (WDK) from Microsoft.
- 2. From the Start menu, in the Windows Driver Kits folder, select Build
- Environments, then your operating system, then the x86 Free Build
- Environment (or one that is appropriate for your system).
- 3. From the console, change directory to the `windows/ddk_build/` directory,
- which is part of the HIDAPI distribution.
- 4. Type build.
- 5. You can find the output files (DLL and LIB) in a subdirectory created
- by the build system which is appropriate for your environment. On
- Windows XP, this directory is `objfre_wxp_x86/i386`.
+If you are looking for information regarding DDK build of HIDAPI
+- the build has been broken for a while and now the support files are obsolete.
diff --git a/custom/dependencies/hidapi/README.md b/custom/dependencies/hidapi/README.md
index 53705cbb3..c2f378f89 100644
--- a/custom/dependencies/hidapi/README.md
+++ b/custom/dependencies/hidapi/README.md
@@ -20,6 +20,7 @@ It was moved to [libusb/hidapi](https://github.com/libusb/hidapi) on June 4th, 2
* [About](#about)
* [Test GUI](#test-gui)
+ * [Console Test App](#console-test-app)
* [What Does the API Look Like?](#what-does-the-api-look-like)
* [License](#license)
* [Installing HIDAPI](#installing-hidapi)
@@ -28,7 +29,7 @@ It was moved to [libusb/hidapi](https://github.com/libusb/hidapi) on June 4th, 2
## About
-HIDAPI has four back-ends:
+### HIDAPI has four back-ends:
* Windows (using `hid.dll`)
* Linux/hidraw (using the Kernel's hidraw driver)
* libusb (using libusb-1.0 - Linux/BSD/other UNIX-like systems)
@@ -45,7 +46,7 @@ for unprivileged users to be able to access HID devices with hidapi. Refer
to the [69-hid.rules](udev/69-hid.rules) file in the `udev` directory
for an example.
-__Linux/hidraw__ (`linux/hid.c`):
+#### __Linux/hidraw__ (`linux/hid.c`):
This back-end uses the hidraw interface in the Linux kernel, and supports
both USB and Bluetooth HID devices. It requires kernel version at least 2.6.39
@@ -55,7 +56,7 @@ Keyboards, mice, and some other devices which are blacklisted from having
hidraw nodes will not work. Fortunately, for nearly all the uses of hidraw,
this is not a problem.
-__Linux/FreeBSD/libusb__ (`libusb/hid.c`):
+#### __Linux/FreeBSD/libusb__ (`libusb/hid.c`):
This back-end uses libusb-1.0 to communicate directly to a USB device. This
back-end will of course not work with Bluetooth devices.
@@ -65,7 +66,7 @@ back-end will of course not work with Bluetooth devices.
HIDAPI also comes with a Test GUI. The Test GUI is cross-platform and uses
Fox Toolkit . It will build on every platform
which HIDAPI supports. Since it relies on a 3rd party library, building it
-is optional but recommended because it is so useful when debugging hardware.
+is optional but it is useful when debugging hardware.
NOTE: Test GUI based on Fox Toolkit is not actively developed nor supported
by HIDAPI team. It is kept as a historical artifact. It may even work sometime
@@ -74,6 +75,14 @@ or on some platforms, but it is not going to get any new features or bugfixes.
Instructions for installing Fox-Toolkit on each platform is not provided.
Make sure to use Fox-Toolkit v1.6 if you choose to use it.
+### Console Test App
+
+If you want to play around with your HID device before starting
+any development with HIDAPI and using a GUI app is not an option for you, you may try [`hidapitester`](https://github.com/todbot/hidapitester).
+
+This app has a console interface for most of the features supported
+by HIDAPI library.
+
## What Does the API Look Like?
The API provides the most commonly used HID functions including sending
@@ -83,15 +92,13 @@ Generic HID sample looks like this (with error checking removed for
simplicity):
**Warning: Only run the code you understand, and only when it conforms to the
-device spec. Writing data at random to your HID devices can break them.**
+device spec. Writing data (`hid_write`) at random to your HID devices can break them.**
```c
-#ifdef WIN32
-#include
-#endif
-#include
-#include
-#include "hidapi.h"
+#include // printf
+#include // wprintf
+
+#include
#define MAX_STR 255
diff --git a/custom/dependencies/hidapi/VERSION b/custom/dependencies/hidapi/VERSION
index eb1336c84..d9df1bbc0 100644
--- a/custom/dependencies/hidapi/VERSION
+++ b/custom/dependencies/hidapi/VERSION
@@ -1 +1 @@
-0.11.0-dev
+0.11.0
diff --git a/custom/dependencies/hidapi/configure.ac b/custom/dependencies/hidapi/configure.ac
index 8d9311cc4..19cc1e607 100644
--- a/custom/dependencies/hidapi/configure.ac
+++ b/custom/dependencies/hidapi/configure.ac
@@ -2,6 +2,9 @@ AC_PREREQ(2.63)
AC_INIT([hidapi],[m4_normalize(m4_builtin([include], VERSION))],[https://github.com/libusb/hidapi/issues])
+echo "This build script for HIDAPI is deprecated."
+echo "Consider using CMake instead."
+
# Library soname version
# Follow the following rules (particularly the ones in the second link):
# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
diff --git a/custom/dependencies/hidapi/hidtest/test.c b/custom/dependencies/hidapi/hidtest/test.c
index bbea421e3..03956ead0 100644
--- a/custom/dependencies/hidapi/hidtest/test.c
+++ b/custom/dependencies/hidapi/hidtest/test.c
@@ -18,7 +18,8 @@
#include
#include
#include
-#include "hidapi.h"
+
+#include
// Headers needed for sleeping.
#ifdef _WIN32
@@ -175,7 +176,7 @@ int main(int argc, char* argv[])
printf("waiting...\n");
if (res < 0)
printf("Unable to read()\n");
- #ifdef WIN32
+ #ifdef _WIN32
Sleep(500);
#else
usleep(500*1000);
@@ -193,7 +194,7 @@ int main(int argc, char* argv[])
/* Free static HIDAPI objects. */
hid_exit();
-#ifdef WIN32
+#ifdef _WIN32
system("pause");
#endif
diff --git a/custom/dependencies/hidapi/libusb/CMakeLists.txt b/custom/dependencies/hidapi/libusb/CMakeLists.txt
index 99e2a9623..f4392d7a8 100644
--- a/custom/dependencies/hidapi/libusb/CMakeLists.txt
+++ b/custom/dependencies/hidapi/libusb/CMakeLists.txt
@@ -1,5 +1,7 @@
cmake_minimum_required(VERSION 3.6.3 FATAL_ERROR)
+list(APPEND HIDAPI_PUBLIC_HEADERS "hidapi_libusb.h")
+
add_library(hidapi_libusb
${HIDAPI_PUBLIC_HEADERS}
hid.c
diff --git a/custom/dependencies/hidapi/libusb/Makefile.am b/custom/dependencies/hidapi/libusb/Makefile.am
index 1da06bc16..6964ebbbc 100644
--- a/custom/dependencies/hidapi/libusb/Makefile.am
+++ b/custom/dependencies/hidapi/libusb/Makefile.am
@@ -29,6 +29,6 @@ libhidapi_la_LIBADD = $(LIBS_LIBUSB)
endif
hdrdir = $(includedir)/hidapi
-hdr_HEADERS = $(top_srcdir)/hidapi/hidapi.h
+hdr_HEADERS = $(top_srcdir)/hidapi/hidapi.h hidapi_libusb.h
EXTRA_DIST = Makefile-manual
diff --git a/custom/dependencies/hidapi/libusb/hid.c b/custom/dependencies/hidapi/libusb/hid.c
index 4e297192a..756a5916c 100644
--- a/custom/dependencies/hidapi/libusb/hid.c
+++ b/custom/dependencies/hidapi/libusb/hid.c
@@ -49,7 +49,7 @@
#include
#endif
-#include "hidapi.h"
+#include "hidapi_libusb.h"
#if defined(__ANDROID__) && __ANDROID_API__ < __ANDROID_API_N__
@@ -569,12 +569,16 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id,
struct libusb_device_descriptor desc;
struct libusb_config_descriptor *conf_desc = NULL;
int j, k;
- int interface_num = 0;
int res = libusb_get_device_descriptor(dev, &desc);
unsigned short dev_vid = desc.idVendor;
unsigned short dev_pid = desc.idProduct;
+ if ((vendor_id != 0x0 && vendor_id != dev_vid) ||
+ (product_id != 0x0 && product_id != dev_pid)) {
+ continue;
+ }
+
res = libusb_get_active_config_descriptor(dev, &conf_desc);
if (res < 0)
libusb_get_config_descriptor(dev, 0, &conf_desc);
@@ -585,129 +589,124 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id,
const struct libusb_interface_descriptor *intf_desc;
intf_desc = &intf->altsetting[k];
if (intf_desc->bInterfaceClass == LIBUSB_CLASS_HID) {
- interface_num = intf_desc->bInterfaceNumber;
-
- /* Check the VID/PID against the arguments */
- if ((vendor_id == 0x0 || vendor_id == dev_vid) &&
- (product_id == 0x0 || product_id == dev_pid)) {
- struct hid_device_info *tmp;
+ int interface_num = intf_desc->bInterfaceNumber;
+ struct hid_device_info *tmp;
- /* VID/PID match. Create the record. */
- tmp = (struct hid_device_info*) calloc(1, sizeof(struct hid_device_info));
- if (cur_dev) {
- cur_dev->next = tmp;
- }
- else {
- root = tmp;
- }
- cur_dev = tmp;
+ /* VID/PID match. Create the record. */
+ tmp = (struct hid_device_info*) calloc(1, sizeof(struct hid_device_info));
+ if (cur_dev) {
+ cur_dev->next = tmp;
+ }
+ else {
+ root = tmp;
+ }
+ cur_dev = tmp;
- /* Fill out the record */
- cur_dev->next = NULL;
- cur_dev->path = make_path(dev, interface_num, conf_desc->bConfigurationValue);
+ /* Fill out the record */
+ cur_dev->next = NULL;
+ cur_dev->path = make_path(dev, interface_num, conf_desc->bConfigurationValue);
- res = libusb_open(dev, &handle);
+ res = libusb_open(dev, &handle);
- if (res >= 0) {
+ if (res >= 0) {
#ifdef __ANDROID__
- /* There is (a potential) libusb Android backend, in which
- device descriptor is not accurate up until the device is opened.
- https://github.com/libusb/libusb/pull/874#discussion_r632801373
- A workaround is to re-read the descriptor again.
- Even if it is not going to be accepted into libusb master,
- having it here won't do any harm, since reading the device descriptor
- is as cheap as copy 18 bytes of data. */
- libusb_get_device_descriptor(dev, &desc);
+ /* There is (a potential) libusb Android backend, in which
+ device descriptor is not accurate up until the device is opened.
+ https://github.com/libusb/libusb/pull/874#discussion_r632801373
+ A workaround is to re-read the descriptor again.
+ Even if it is not going to be accepted into libusb master,
+ having it here won't do any harm, since reading the device descriptor
+ is as cheap as copy 18 bytes of data. */
+ libusb_get_device_descriptor(dev, &desc);
#endif
- /* Serial Number */
- if (desc.iSerialNumber > 0)
- cur_dev->serial_number =
- get_usb_string(handle, desc.iSerialNumber);
+ /* Serial Number */
+ if (desc.iSerialNumber > 0)
+ cur_dev->serial_number =
+ get_usb_string(handle, desc.iSerialNumber);
- /* Manufacturer and Product strings */
- if (desc.iManufacturer > 0)
- cur_dev->manufacturer_string =
- get_usb_string(handle, desc.iManufacturer);
- if (desc.iProduct > 0)
- cur_dev->product_string =
- get_usb_string(handle, desc.iProduct);
+ /* Manufacturer and Product strings */
+ if (desc.iManufacturer > 0)
+ cur_dev->manufacturer_string =
+ get_usb_string(handle, desc.iManufacturer);
+ if (desc.iProduct > 0)
+ cur_dev->product_string =
+ get_usb_string(handle, desc.iProduct);
#ifdef INVASIVE_GET_USAGE
{
- /*
- This section is removed because it is too
- invasive on the system. Getting a Usage Page
- and Usage requires parsing the HID Report
- descriptor. Getting a HID Report descriptor
- involves claiming the interface. Claiming the
- interface involves detaching the kernel driver.
- Detaching the kernel driver is hard on the system
- because it will unclaim interfaces (if another
- app has them claimed) and the re-attachment of
- the driver will sometimes change /dev entry names.
- It is for these reasons that this section is
- #if 0. For composite devices, use the interface
- field in the hid_device_info struct to distinguish
- between interfaces. */
- unsigned char data[256];
+ /*
+ This section is removed because it is too
+ invasive on the system. Getting a Usage Page
+ and Usage requires parsing the HID Report
+ descriptor. Getting a HID Report descriptor
+ involves claiming the interface. Claiming the
+ interface involves detaching the kernel driver.
+ Detaching the kernel driver is hard on the system
+ because it will unclaim interfaces (if another
+ app has them claimed) and the re-attachment of
+ the driver will sometimes change /dev entry names.
+ It is for these reasons that this section is
+ #if 0. For composite devices, use the interface
+ field in the hid_device_info struct to distinguish
+ between interfaces. */
+ unsigned char data[256];
#ifdef DETACH_KERNEL_DRIVER
- int detached = 0;
- /* Usage Page and Usage */
- res = libusb_kernel_driver_active(handle, interface_num);
- if (res == 1) {
- res = libusb_detach_kernel_driver(handle, interface_num);
- if (res < 0)
- LOG("Couldn't detach kernel driver, even though a kernel driver was attached.");
- else
- detached = 1;
- }
+ int detached = 0;
+ /* Usage Page and Usage */
+ res = libusb_kernel_driver_active(handle, interface_num);
+ if (res == 1) {
+ res = libusb_detach_kernel_driver(handle, interface_num);
+ if (res < 0)
+ LOG("Couldn't detach kernel driver, even though a kernel driver was attached.\n");
+ else
+ detached = 1;
+ }
#endif
- res = libusb_claim_interface(handle, interface_num);
+ res = libusb_claim_interface(handle, interface_num);
+ if (res >= 0) {
+ /* Get the HID Report Descriptor. */
+ res = libusb_control_transfer(handle, LIBUSB_ENDPOINT_IN|LIBUSB_RECIPIENT_INTERFACE, LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_REPORT << 8)|interface_num, 0, data, sizeof(data), 5000);
if (res >= 0) {
- /* Get the HID Report Descriptor. */
- res = libusb_control_transfer(handle, LIBUSB_ENDPOINT_IN|LIBUSB_RECIPIENT_INTERFACE, LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_REPORT << 8)|interface_num, 0, data, sizeof(data), 5000);
- if (res >= 0) {
- unsigned short page=0, usage=0;
- /* Parse the usage and usage page
- out of the report descriptor. */
- get_usage(data, res, &page, &usage);
- cur_dev->usage_page = page;
- cur_dev->usage = usage;
- }
- else
- LOG("libusb_control_transfer() for getting the HID report failed with %d\n", res);
-
- /* Release the interface */
- res = libusb_release_interface(handle, interface_num);
- if (res < 0)
- LOG("Can't release the interface.\n");
+ unsigned short page=0, usage=0;
+ /* Parse the usage and usage page
+ out of the report descriptor. */
+ get_usage(data, res, &page, &usage);
+ cur_dev->usage_page = page;
+ cur_dev->usage = usage;
}
else
- LOG("Can't claim interface %d\n", res);
+ LOG("libusb_control_transfer() for getting the HID report failed with %d\n", res);
+
+ /* Release the interface */
+ res = libusb_release_interface(handle, interface_num);
+ if (res < 0)
+ LOG("Can't release the interface.\n");
+ }
+ else
+ LOG("Can't claim interface %d\n", res);
#ifdef DETACH_KERNEL_DRIVER
- /* Re-attach kernel driver if necessary. */
- if (detached) {
- res = libusb_attach_kernel_driver(handle, interface_num);
- if (res < 0)
- LOG("Couldn't re-attach kernel driver.\n");
- }
+ /* Re-attach kernel driver if necessary. */
+ if (detached) {
+ res = libusb_attach_kernel_driver(handle, interface_num);
+ if (res < 0)
+ LOG("Couldn't re-attach kernel driver.\n");
+ }
#endif
}
#endif /* INVASIVE_GET_USAGE */
- libusb_close(handle);
- }
- /* VID/PID */
- cur_dev->vendor_id = dev_vid;
- cur_dev->product_id = dev_pid;
+ libusb_close(handle);
+ }
+ /* VID/PID */
+ cur_dev->vendor_id = dev_vid;
+ cur_dev->product_id = dev_pid;
- /* Release Number */
- cur_dev->release_number = desc.bcdDevice;
+ /* Release Number */
+ cur_dev->release_number = desc.bcdDevice;
- /* Interface Number */
- cur_dev->interface_number = interface_num;
- }
+ /* Interface Number */
+ cur_dev->interface_number = interface_num;
}
} /* altsettings */
} /* interfaces */
@@ -910,13 +909,95 @@ static void *read_thread(void *param)
}
+static int hidapi_initialize_device(hid_device *dev, const struct libusb_interface_descriptor *intf_desc)
+{
+ int i =0;
+ int res = 0;
+ struct libusb_device_descriptor desc;
+ libusb_get_device_descriptor(libusb_get_device(dev->device_handle), &desc);
+
+#ifdef DETACH_KERNEL_DRIVER
+ /* Detach the kernel driver, but only if the
+ device is managed by the kernel */
+ dev->is_driver_detached = 0;
+ if (libusb_kernel_driver_active(dev->device_handle, intf_desc->bInterfaceNumber) == 1) {
+ res = libusb_detach_kernel_driver(dev->device_handle, intf_desc->bInterfaceNumber);
+ if (res < 0) {
+ libusb_close(dev->device_handle);
+ LOG("Unable to detach Kernel Driver\n");
+ return 0;
+ }
+ else {
+ dev->is_driver_detached = 1;
+ LOG("Driver successfully detached from kernel.\n");
+ }
+ }
+#endif
+ res = libusb_claim_interface(dev->device_handle, intf_desc->bInterfaceNumber);
+ if (res < 0) {
+ LOG("can't claim interface %d: %d\n", intf_desc->bInterfaceNumber, res);
+ return 0;
+ }
+
+ /* Store off the string descriptor indexes */
+ dev->manufacturer_index = desc.iManufacturer;
+ dev->product_index = desc.iProduct;
+ dev->serial_index = desc.iSerialNumber;
+
+ /* Store off the interface number */
+ dev->interface = intf_desc->bInterfaceNumber;
+
+ dev->input_endpoint = 0;
+ dev->input_ep_max_packet_size = 0;
+ dev->output_endpoint = 0;
+
+ /* Find the INPUT and OUTPUT endpoints. An
+ OUTPUT endpoint is not required. */
+ for (i = 0; i < intf_desc->bNumEndpoints; i++) {
+ const struct libusb_endpoint_descriptor *ep
+ = &intf_desc->endpoint[i];
+
+ /* Determine the type and direction of this
+ endpoint. */
+ int is_interrupt =
+ (ep->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK)
+ == LIBUSB_TRANSFER_TYPE_INTERRUPT;
+ int is_output =
+ (ep->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK)
+ == LIBUSB_ENDPOINT_OUT;
+ int is_input =
+ (ep->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK)
+ == LIBUSB_ENDPOINT_IN;
+
+ /* Decide whether to use it for input or output. */
+ if (dev->input_endpoint == 0 &&
+ is_interrupt && is_input) {
+ /* Use this endpoint for INPUT */
+ dev->input_endpoint = ep->bEndpointAddress;
+ dev->input_ep_max_packet_size = ep->wMaxPacketSize;
+ }
+ if (dev->output_endpoint == 0 &&
+ is_interrupt && is_output) {
+ /* Use this endpoint for OUTPUT */
+ dev->output_endpoint = ep->bEndpointAddress;
+ }
+ }
+
+ pthread_create(&dev->thread, NULL, read_thread, dev);
+
+ /* Wait here for the read thread to be initialized. */
+ pthread_barrier_wait(&dev->barrier);
+ return 1;
+}
+
+
hid_device * HID_API_EXPORT hid_open_path(const char *path)
{
hid_device *dev = NULL;
- libusb_device **devs;
- libusb_device *usb_dev;
- int res;
+ libusb_device **devs = NULL;
+ libusb_device *usb_dev = NULL;
+ int res = 0;
int d = 0;
int good_open = 0;
@@ -926,19 +1007,16 @@ hid_device * HID_API_EXPORT hid_open_path(const char *path)
dev = new_hid_device();
libusb_get_device_list(usb_context, &devs);
- while ((usb_dev = devs[d++]) != NULL) {
- struct libusb_device_descriptor desc;
+ while ((usb_dev = devs[d++]) != NULL && !good_open) {
struct libusb_config_descriptor *conf_desc = NULL;
- int i,j,k;
- libusb_get_device_descriptor(usb_dev, &desc);
+ int j,k;
if (libusb_get_active_config_descriptor(usb_dev, &conf_desc) < 0)
continue;
- for (j = 0; j < conf_desc->bNumInterfaces; j++) {
+ for (j = 0; j < conf_desc->bNumInterfaces && !good_open; j++) {
const struct libusb_interface *intf = &conf_desc->interface[j];
- for (k = 0; k < intf->num_altsetting; k++) {
- const struct libusb_interface_descriptor *intf_desc;
- intf_desc = &intf->altsetting[k];
+ for (k = 0; k < intf->num_altsetting && !good_open; k++) {
+ const struct libusb_interface_descriptor *intf_desc = &intf->altsetting[k];
if (intf_desc->bInterfaceClass == LIBUSB_CLASS_HID) {
char *dev_path = make_path(usb_dev, intf_desc->bInterfaceNumber, conf_desc->bConfigurationValue);
if (!strcmp(dev_path, path)) {
@@ -951,93 +1029,15 @@ hid_device * HID_API_EXPORT hid_open_path(const char *path)
free(dev_path);
break;
}
- good_open = 1;
-
-#ifdef __ANDROID__
- /* See remark in hid_enumerate */
- libusb_get_device_descriptor(usb_dev, &desc);
-#endif
-
-#ifdef DETACH_KERNEL_DRIVER
- /* Detach the kernel driver, but only if the
- device is managed by the kernel */
- dev->is_driver_detached = 0;
- if (libusb_kernel_driver_active(dev->device_handle, intf_desc->bInterfaceNumber) == 1) {
- res = libusb_detach_kernel_driver(dev->device_handle, intf_desc->bInterfaceNumber);
- if (res < 0) {
- libusb_close(dev->device_handle);
- LOG("Unable to detach Kernel Driver\n");
- free(dev_path);
- good_open = 0;
- break;
- }
- else {
- dev->is_driver_detached = 1;
- LOG("Driver successfully detached from kernel.\n");
- }
- }
-#endif
- res = libusb_claim_interface(dev->device_handle, intf_desc->bInterfaceNumber);
- if (res < 0) {
- LOG("can't claim interface %d: %d\n", intf_desc->bInterfaceNumber, res);
- free(dev_path);
+ good_open = hidapi_initialize_device(dev, intf_desc);
+ if (!good_open)
libusb_close(dev->device_handle);
- good_open = 0;
- break;
- }
-
- /* Store off the string descriptor indexes */
- dev->manufacturer_index = desc.iManufacturer;
- dev->product_index = desc.iProduct;
- dev->serial_index = desc.iSerialNumber;
-
- /* Store off the interface number */
- dev->interface = intf_desc->bInterfaceNumber;
-
- /* Find the INPUT and OUTPUT endpoints. An
- OUTPUT endpoint is not required. */
- for (i = 0; i < intf_desc->bNumEndpoints; i++) {
- const struct libusb_endpoint_descriptor *ep
- = &intf_desc->endpoint[i];
-
- /* Determine the type and direction of this
- endpoint. */
- int is_interrupt =
- (ep->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK)
- == LIBUSB_TRANSFER_TYPE_INTERRUPT;
- int is_output =
- (ep->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK)
- == LIBUSB_ENDPOINT_OUT;
- int is_input =
- (ep->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK)
- == LIBUSB_ENDPOINT_IN;
-
- /* Decide whether to use it for input or output. */
- if (dev->input_endpoint == 0 &&
- is_interrupt && is_input) {
- /* Use this endpoint for INPUT */
- dev->input_endpoint = ep->bEndpointAddress;
- dev->input_ep_max_packet_size = ep->wMaxPacketSize;
- }
- if (dev->output_endpoint == 0 &&
- is_interrupt && is_output) {
- /* Use this endpoint for OUTPUT */
- dev->output_endpoint = ep->bEndpointAddress;
- }
- }
-
- pthread_create(&dev->thread, NULL, read_thread, dev);
-
- /* Wait here for the read thread to be initialized. */
- pthread_barrier_wait(&dev->barrier);
-
}
free(dev_path);
}
}
}
libusb_free_config_descriptor(conf_desc);
-
}
libusb_free_device_list(devs, 1);
@@ -1054,6 +1054,80 @@ hid_device * HID_API_EXPORT hid_open_path(const char *path)
}
+HID_API_EXPORT hid_device * HID_API_CALL hid_libusb_wrap_sys_device(intptr_t sys_dev, int interface_num)
+{
+/* 0x01000107 is a LIBUSB_API_VERSION for 1.0.23 - version when libusb_wrap_sys_device was introduced */
+#if (!defined(HIDAPI_TARGET_LIBUSB_API_VERSION) || HIDAPI_TARGET_LIBUSB_API_VERSION >= 0x01000107) && (LIBUSB_API_VERSION >= 0x01000107)
+ hid_device *dev = NULL;
+ struct libusb_config_descriptor *conf_desc = NULL;
+ const struct libusb_interface_descriptor *selected_intf_desc = NULL;
+ int res = 0;
+ int j = 0, k = 0;
+
+ if(hid_init() < 0)
+ return NULL;
+
+ dev = new_hid_device();
+
+ res = libusb_wrap_sys_device(usb_context, sys_dev, &dev->device_handle);
+ if (res < 0) {
+ LOG("libusb_wrap_sys_device failed: %d %s\n", res, libusb_error_name(res));
+ goto err;
+ }
+
+ res = libusb_get_active_config_descriptor(libusb_get_device(dev->device_handle), &conf_desc);
+ if (res < 0)
+ libusb_get_config_descriptor(libusb_get_device(dev->device_handle), 0, &conf_desc);
+
+ if (!conf_desc) {
+ LOG("Failed to get configuration descriptor: %d %s\n", res, libusb_error_name(res));
+ goto err;
+ }
+
+ /* find matching HID interface */
+ for (j = 0; j < conf_desc->bNumInterfaces && !selected_intf_desc; j++) {
+ const struct libusb_interface *intf = &conf_desc->interface[j];
+ for (k = 0; k < intf->num_altsetting; k++) {
+ const struct libusb_interface_descriptor *intf_desc = &intf->altsetting[k];
+ if (intf_desc->bInterfaceClass == LIBUSB_CLASS_HID) {
+ if (interface_num < 0 || interface_num == intf_desc->bInterfaceNumber) {
+ selected_intf_desc = intf_desc;
+ break;
+ }
+ }
+ }
+ }
+
+ if (!selected_intf_desc) {
+ if (interface_num < 0) {
+ LOG("Sys USB device doesn't contain a HID interface\n");
+ }
+ else {
+ LOG("Sys USB device doesn't contain a HID interface with number %d\n", interface_num);
+ }
+ goto err;
+ }
+
+ if (!hidapi_initialize_device(dev, selected_intf_desc))
+ goto err;
+
+ return dev;
+
+err:
+ if (conf_desc)
+ libusb_free_config_descriptor(conf_desc);
+ if (dev->device_handle)
+ libusb_close(dev->device_handle);
+ free_hid_device(dev);
+#else
+ (void)sys_dev;
+ (void)interface_num;
+ LOG("libusb_wrap_sys_device is not available\n");
+#endif
+ return NULL;
+}
+
+
int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length)
{
int res;
diff --git a/custom/dependencies/hidapi/libusb/hidapi_libusb.h b/custom/dependencies/hidapi/libusb/hidapi_libusb.h
new file mode 100644
index 000000000..1f56c2c51
--- /dev/null
+++ b/custom/dependencies/hidapi/libusb/hidapi_libusb.h
@@ -0,0 +1,54 @@
+/*******************************************************
+ HIDAPI - Multi-Platform library for
+ communication with HID devices.
+
+ libusb/hidapi Team
+
+ Copyright 2021, All Rights Reserved.
+
+ At the discretion of the user of this library,
+ this software may be licensed under the terms of the
+ GNU General Public License v3, a BSD-Style license, or the
+ original HIDAPI license as outlined in the LICENSE.txt,
+ LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
+ files located at the root of the source distribution.
+ These files may also be found in the public source
+ code repository located at:
+ https://github.com/libusb/hidapi .
+********************************************************/
+
+/** @file
+ * @defgroup API hidapi API
+ */
+
+#ifndef HIDAPI_LIBUSB_H__
+#define HIDAPI_LIBUSB_H__
+
+#include
+
+#include "hidapi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ /** @brief Open a HID device using libusb_wrap_sys_device.
+ See https://libusb.sourceforge.io/api-1.0/group__libusb__dev.html#ga98f783e115ceff4eaf88a60e6439563c,
+ for details on libusb_wrap_sys_device.
+
+ @ingroup API
+ @param sys_dev Platform-specific file descriptor that can be recognised by libusb.
+ @param interface_num USB interface number of the device to be used as HID interface.
+ Pass -1 to select first HID interface of the device.
+
+ @returns
+ This function returns a pointer to a #hid_device object on
+ success or NULL on failure.
+ */
+ HID_API_EXPORT hid_device * HID_API_CALL hid_libusb_wrap_sys_device(intptr_t sys_dev, int interface_num);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/custom/dependencies/hidapi/mac/hid.c b/custom/dependencies/hidapi/mac/hid.c
index 868244254..12648d9cf 100644
--- a/custom/dependencies/hidapi/mac/hid.c
+++ b/custom/dependencies/hidapi/mac/hid.c
@@ -381,7 +381,7 @@ static struct hid_device_info *create_device_info_with_usage(IOHIDDeviceRef dev,
struct hid_device_info *cur_dev;
io_object_t iokit_dev;
kern_return_t res;
- io_string_t path;
+ uint64_t entry_id;
if (dev == NULL) {
return NULL;
@@ -401,13 +401,30 @@ static struct hid_device_info *create_device_info_with_usage(IOHIDDeviceRef dev,
/* Fill out the record */
cur_dev->next = NULL;
- /* Fill in the path (IOService plane) */
+ /* Fill in the path (as a unique ID of the service entry) */
+ cur_dev->path = NULL;
iokit_dev = IOHIDDeviceGetService(dev);
- res = IORegistryEntryGetPath(iokit_dev, kIOServicePlane, path);
- if (res == KERN_SUCCESS)
- cur_dev->path = strdup(path);
- else
+ if (iokit_dev != MACH_PORT_NULL) {
+ res = IORegistryEntryGetRegistryEntryID(iokit_dev, &entry_id);
+ }
+ else {
+ res = KERN_INVALID_ARGUMENT;
+ }
+
+ if (res == KERN_SUCCESS) {
+ /* max value of entry_id(uint64_t) is 18446744073709551615 which is 20 characters long,
+ so for (max) "path" string 'DevSrvsID:18446744073709551615' we would need
+ 9+1+20+1=31 bytes byffer, but allocate 32 for simple alignment */
+ cur_dev->path = calloc(1, 32);
+ if (cur_dev->path != NULL) {
+ sprintf(cur_dev->path, "DevSrvsID:%llu", entry_id);
+ }
+ }
+
+ if (cur_dev->path == NULL) {
+ /* for whatever reason, trying to keep it a non-NULL string */
cur_dev->path = strdup("");
+ }
/* Serial Number */
get_serial_number(dev, buf, BUF_LEN);
@@ -759,11 +776,33 @@ static void *read_thread(void *param)
return NULL;
}
-/* hid_open_path()
- *
- * path must be a valid path to an IOHIDDevice in the IOService plane
- * Example: "IOService:/AppleACPIPlatformExpert/PCI0@0/AppleACPIPCI/EHC1@1D,7/AppleUSBEHCI/PLAYSTATION(R)3 Controller@fd120000/IOUSBInterface@0/IOUSBHIDDriver"
- */
+/* \p path must be one of:
+ - in format 'DevSrvsID:' (as returned by hid_enumerate);
+ - a valid path to an IOHIDDevice in the IOService plane (as returned by IORegistryEntryGetPath,
+ e.g.: "IOService:/AppleACPIPlatformExpert/PCI0@0/AppleACPIPCI/EHC1@1D,7/AppleUSBEHCI/PLAYSTATION(R)3 Controller@fd120000/IOUSBInterface@0/IOUSBHIDDriver");
+ Second format is for compatibility with paths accepted by older versions of HIDAPI.
+*/
+static io_registry_entry_t hid_open_service_registry_from_path(const char *path)
+{
+ if (path == NULL)
+ return MACH_PORT_NULL;
+
+ /* Get the IORegistry entry for the given path */
+ if (strncmp("DevSrvsID:", path, 10) == 0) {
+ char *endptr;
+ uint64_t entry_id = strtoull(path + 10, &endptr, 10);
+ if (*endptr == '\0') {
+ return IOServiceGetMatchingService(kIOMasterPortDefault, IORegistryEntryIDMatching(entry_id));
+ }
+ }
+ else {
+ /* Fallback to older format of the path */
+ return IORegistryEntryFromPath(kIOMasterPortDefault, path);
+ }
+
+ return MACH_PORT_NULL;
+}
+
hid_device * HID_API_EXPORT hid_open_path(const char *path)
{
hid_device *dev = NULL;
@@ -777,7 +816,7 @@ hid_device * HID_API_EXPORT hid_open_path(const char *path)
dev = new_hid_device();
/* Get the IORegistry entry for the given path */
- entry = IORegistryEntryFromPath(kIOMasterPortDefault, path);
+ entry = hid_open_service_registry_from_path(path);
if (entry == MACH_PORT_NULL) {
/* Path wasn't valid (maybe device was removed?) */
goto return_error;
diff --git a/custom/dependencies/hidapi/src/CMakeLists.txt b/custom/dependencies/hidapi/src/CMakeLists.txt
index ae59369ed..8f454e53f 100644
--- a/custom/dependencies/hidapi/src/CMakeLists.txt
+++ b/custom/dependencies/hidapi/src/CMakeLists.txt
@@ -125,6 +125,9 @@ else()
set(HIDAPI_WITH_LIBUSB ON)
endif()
if(HIDAPI_WITH_LIBUSB)
+ target_include_directories(hidapi_include INTERFACE
+ "$"
+ )
add_subdirectory("${PROJECT_ROOT}/libusb" libusb)
list(APPEND EXPORT_COMPONENTS libusb)
if(NOT EXPORT_ALIAS)
diff --git a/custom/dependencies/hidapi/udev/69-hid.rules b/custom/dependencies/hidapi/udev/69-hid.rules
index dc2df9045..a27113ca8 100644
--- a/custom/dependencies/hidapi/udev/69-hid.rules
+++ b/custom/dependencies/hidapi/udev/69-hid.rules
@@ -7,7 +7,7 @@
# those of your device.
# HIDAPI/libusb
-SUBSYSTEM=="usb", ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="003f", TAG+="uaccess"
+SUBSYSTEMS=="usb", ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="003f", TAG+="uaccess"
# If you are using the hidraw implementation (linux/hid.c), then do something
# like the following, substituting the VID and PID with your device.
@@ -16,8 +16,11 @@ SUBSYSTEM=="usb", ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="003f", TAG+="uacce
KERNEL=="hidraw*", ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="003f", TAG+="uaccess"
# Once done, optionally rename this file for your application, and drop it into
-# /etc/udev/rules.d. Note that these rules must have priorty before 70-uaccess.rules
-# for example, name the file /etc/udev/rules.d/69-my-application-hid.rules.
+# /etc/udev/rules.d/.
+# NOTE: these rules must have priorty before 73-seat-late.rules.
+# (Small discussion/explanation in systemd repo:
+# https://github.com/systemd/systemd/issues/4288#issuecomment-348166161)
+# for example, name the file /etc/udev/rules.d/70-my-application-hid.rules.
# Then, replug your device or run:
# sudo udevadm control --reload-rules && sudo udevadm trigger
@@ -25,8 +28,8 @@ KERNEL=="hidraw*", ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="003f", TAG+="uacc
# must be lower case.
# TAG+="uaccess" only gives permission to physically present users, which
-# is appropriate in most scenarios. If you require remote access to the
-# device, add
+# is appropriate in most scenarios. If you require access to the device
+# from a remote session (e.g. over SSH), add
# GROUP="plugdev", MODE="660"
# to the end of the udev rule lines, add your user to the plugdev group with:
# usermod -aG plugdev USERNAME
diff --git a/custom/dependencies/hidapi/windows/Makefile.am b/custom/dependencies/hidapi/windows/Makefile.am
index 97e261ac9..2ea5c0d8b 100644
--- a/custom/dependencies/hidapi/windows/Makefile.am
+++ b/custom/dependencies/hidapi/windows/Makefile.am
@@ -8,7 +8,6 @@ hdrdir = $(includedir)/hidapi
hdr_HEADERS = $(top_srcdir)/hidapi/hidapi.h
EXTRA_DIST = \
- ddk_build \
hidapi.vcproj \
hidtest.vcproj \
Makefile-manual \
diff --git a/custom/dependencies/hidapi/windows/ddk_build/.gitignore b/custom/dependencies/hidapi/windows/ddk_build/.gitignore
deleted file mode 100644
index 823ff0b2c..000000000
--- a/custom/dependencies/hidapi/windows/ddk_build/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-*.log
-obj*_*_*
\ No newline at end of file
diff --git a/custom/dependencies/hidapi/windows/ddk_build/hidapi.def b/custom/dependencies/hidapi/windows/ddk_build/hidapi.def
deleted file mode 100644
index 01fe47d64..000000000
--- a/custom/dependencies/hidapi/windows/ddk_build/hidapi.def
+++ /dev/null
@@ -1,18 +0,0 @@
-LIBRARY hidapi
-EXPORTS
- hid_open @1
- hid_write @2
- hid_read @3
- hid_close @4
- hid_get_product_string @5
- hid_get_manufacturer_string @6
- hid_get_serial_number_string @7
- hid_get_indexed_string @8
- hid_error @9
- hid_set_nonblocking @10
- hid_enumerate @11
- hid_open_path @12
- hid_send_feature_report @13
- hid_get_feature_report @14
- hid_get_input_report @15
-
\ No newline at end of file
diff --git a/custom/dependencies/hidapi/windows/ddk_build/makefile b/custom/dependencies/hidapi/windows/ddk_build/makefile
deleted file mode 100644
index 637f712a4..000000000
--- a/custom/dependencies/hidapi/windows/ddk_build/makefile
+++ /dev/null
@@ -1,49 +0,0 @@
-#############################################################################
-#
-# Copyright (C) Microsoft Corporation 1995, 1996
-# All Rights Reserved.
-#
-# MAKEFILE for HID directory
-#
-#############################################################################
-
-!IFDEF WIN95_BUILD
-
-ROOT=..\..\..\..
-
-VERSIONLIST = debug retail
-IS_32 = TRUE
-IS_SDK = TRUE
-IS_PRIVATE = TRUE
-IS_SDK = TRUE
-IS_DDK = TRUE
-WIN32 = TRUE
-COMMONMKFILE = hidapi.mk
-
-!include $(ROOT)\dev\master.mk
-
-
-!ELSE
-
-#
-# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
-# file to this component. This file merely indirects to the real make file
-# that is shared by all the driver components of the Windows NT DDK
-#
-
-!IF DEFINED(_NT_TARGET_VERSION)
-! IF $(_NT_TARGET_VERSION)>=0x501
-! INCLUDE $(NTMAKEENV)\makefile.def
-! ELSE
-# Only warn once per directory
-! INCLUDE $(NTMAKEENV)\makefile.plt
-! IF "$(BUILD_PASS)"=="PASS1"
-! message BUILDMSG: Warning : The sample "$(MAKEDIR)" is not valid for the current OS target.
-! ENDIF
-! ENDIF
-!ELSE
-! INCLUDE $(NTMAKEENV)\makefile.def
-!ENDIF
-
-!ENDIF
-
diff --git a/custom/dependencies/hidapi/windows/ddk_build/sources b/custom/dependencies/hidapi/windows/ddk_build/sources
deleted file mode 100644
index 7f06a0963..000000000
--- a/custom/dependencies/hidapi/windows/ddk_build/sources
+++ /dev/null
@@ -1,23 +0,0 @@
-TARGETNAME=hidapi
-TARGETTYPE=DYNLINK
-UMTYPE=console
-UMENTRY=main
-
-MSC_WARNING_LEVEL=/W3 /WX
-
-TARGETLIBS=$(SDK_LIB_PATH)\hid.lib \
- $(SDK_LIB_PATH)\setupapi.lib \
- $(SDK_LIB_PATH)\kernel32.lib \
- $(SDK_LIB_PATH)\comdlg32.lib
-
-USE_MSVCRT=1
-
-INCLUDES= ..\..\hidapi
-SOURCES= ..\hid.c \
-
-
-TARGET_DESTINATION=retail
-
-MUI=0
-MUI_COMMENT="HID Interface DLL"
-
diff --git a/custom/dependencies/hidapi/windows/hid.c b/custom/dependencies/hidapi/windows/hid.c
index 61fa7e23c..6d8394cdc 100644
--- a/custom/dependencies/hidapi/windows/hid.c
+++ b/custom/dependencies/hidapi/windows/hid.c
@@ -8,7 +8,7 @@
8/22/2009
Copyright 2009, All Rights Reserved.
-
+
At the discretion of the user of this library,
this software may be licensed under the terms of the
GNU General Public License v3, a BSD-Style license, or the
@@ -20,6 +20,12 @@
https://github.com/libusb/hidapi .
********************************************************/
+#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
+// Do not warn about mbsrtowcs and wcsncpy usage.
+// https://docs.microsoft.com/cpp/c-runtime-library/security-features-in-the-crt
+#define _CRT_SECURE_NO_WARNINGS
+#endif
+
#include
#ifndef _NTDEF_
@@ -27,6 +33,7 @@ typedef LONG NTSTATUS;
#endif
#ifdef __MINGW32__
+#include
#include
#include
#endif
@@ -63,18 +70,14 @@ extern "C" {
#include
#include
-
+#include
+#include
#include "hidapi.h"
#undef MIN
#define MIN(x,y) ((x) < (y)? (x): (y))
-#ifdef _MSC_VER
- /* Thanks Microsoft, but I know how to use strncpy(). */
- #pragma warning(disable:4996)
-#endif
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -110,6 +113,7 @@ static struct hid_api_version api_version = {
typedef void* PHIDP_PREPARSED_DATA;
#define HIDP_STATUS_SUCCESS 0x110000
+ typedef void (__stdcall *HidD_GetHidGuid_)(LPGUID hid_guid);
typedef BOOLEAN (__stdcall *HidD_GetAttributes_)(HANDLE device, PHIDD_ATTRIBUTES attrib);
typedef BOOLEAN (__stdcall *HidD_GetSerialNumberString_)(HANDLE device, PVOID buffer, ULONG buffer_len);
typedef BOOLEAN (__stdcall *HidD_GetManufacturerString_)(HANDLE handle, PVOID buffer, ULONG buffer_len);
@@ -123,6 +127,7 @@ static struct hid_api_version api_version = {
typedef NTSTATUS (__stdcall *HidP_GetCaps_)(PHIDP_PREPARSED_DATA preparsed_data, HIDP_CAPS *caps);
typedef BOOLEAN (__stdcall *HidD_SetNumInputBuffers_)(HANDLE handle, ULONG number_buffers);
+ static HidD_GetHidGuid_ HidD_GetHidGuid;
static HidD_GetAttributes_ HidD_GetAttributes;
static HidD_GetSerialNumberString_ HidD_GetSerialNumberString;
static HidD_GetManufacturerString_ HidD_GetManufacturerString;
@@ -138,6 +143,34 @@ static struct hid_api_version api_version = {
static HMODULE lib_handle = NULL;
static BOOLEAN initialized = FALSE;
+
+ typedef DWORD RETURN_TYPE;
+ typedef RETURN_TYPE CONFIGRET;
+ typedef DWORD DEVNODE, DEVINST;
+ typedef DEVNODE* PDEVNODE, * PDEVINST;
+ typedef WCHAR* DEVNODEID_W, * DEVINSTID_W;
+
+#define CR_SUCCESS (0x00000000)
+#define CR_BUFFER_SMALL (0x0000001A)
+
+#define CM_LOCATE_DEVNODE_NORMAL 0x00000000
+
+#define DEVPROP_TYPEMOD_LIST 0x00002000
+
+#define DEVPROP_TYPE_STRING 0x00000012
+#define DEVPROP_TYPE_STRING_LIST (DEVPROP_TYPE_STRING|DEVPROP_TYPEMOD_LIST)
+
+ typedef CONFIGRET(__stdcall* CM_Locate_DevNodeW_)(PDEVINST pdnDevInst, DEVINSTID_W pDeviceID, ULONG ulFlags);
+ typedef CONFIGRET(__stdcall* CM_Get_Parent_)(PDEVINST pdnDevInst, DEVINST dnDevInst, ULONG ulFlags);
+ typedef CONFIGRET(__stdcall* CM_Get_DevNode_PropertyW_)(DEVINST dnDevInst, CONST DEVPROPKEY* PropertyKey, DEVPROPTYPE* PropertyType, PBYTE PropertyBuffer, PULONG PropertyBufferSize, ULONG ulFlags);
+ typedef CONFIGRET(__stdcall* CM_Get_Device_Interface_PropertyW_)(LPCWSTR pszDeviceInterface, CONST DEVPROPKEY* PropertyKey, DEVPROPTYPE* PropertyType, PBYTE PropertyBuffer, PULONG PropertyBufferSize, ULONG ulFlags);
+
+ static CM_Locate_DevNodeW_ CM_Locate_DevNodeW = NULL;
+ static CM_Get_Parent_ CM_Get_Parent = NULL;
+ static CM_Get_DevNode_PropertyW_ CM_Get_DevNode_PropertyW = NULL;
+ static CM_Get_Device_Interface_PropertyW_ CM_Get_Device_Interface_PropertyW = NULL;
+
+ static HMODULE cfgmgr32_lib_handle = NULL;
#endif /* HIDAPI_USE_DDK */
struct hid_device_ {
@@ -153,7 +186,8 @@ struct hid_device_ {
BOOL read_pending;
char *read_buf;
OVERLAPPED ol;
- OVERLAPPED write_ol;
+ OVERLAPPED write_ol;
+ struct hid_device_info* device_info;
};
static hid_device *new_hid_device()
@@ -173,7 +207,8 @@ static hid_device *new_hid_device()
memset(&dev->ol, 0, sizeof(dev->ol));
dev->ol.hEvent = CreateEvent(NULL, FALSE, FALSE /*initial state f=nonsignaled*/, NULL);
memset(&dev->write_ol, 0, sizeof(dev->write_ol));
- dev->write_ol.hEvent = CreateEvent(NULL, FALSE, FALSE /*inital state f=nonsignaled*/, NULL);
+ dev->write_ol.hEvent = CreateEvent(NULL, FALSE, FALSE /*inital state f=nonsignaled*/, NULL);
+ dev->device_info = NULL;
return dev;
}
@@ -181,12 +216,13 @@ static hid_device *new_hid_device()
static void free_hid_device(hid_device *dev)
{
CloseHandle(dev->ol.hEvent);
- CloseHandle(dev->write_ol.hEvent);
+ CloseHandle(dev->write_ol.hEvent);
CloseHandle(dev->device_handle);
LocalFree(dev->last_error_str);
free(dev->write_buf);
free(dev->feature_buf);
free(dev->read_buf);
+ free(dev->device_info);
free(dev);
}
@@ -202,13 +238,13 @@ static void register_error(hid_device *dev, const char *op)
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPWSTR)&msg, 0/*sz*/,
NULL);
-
+
/* Get rid of the CR and LF that FormatMessage() sticks at the
end of the message. Thanks Microsoft! */
ptr = msg;
while (*ptr) {
- if (*ptr == '\r') {
- *ptr = 0x0000;
+ if (*ptr == L'\r') {
+ *ptr = L'\0';
break;
}
ptr++;
@@ -230,6 +266,7 @@ static int lookup_functions()
# pragma GCC diagnostic ignored "-Wcast-function-type"
#endif
#define RESOLVE(x) x = (x##_)GetProcAddress(lib_handle, #x); if (!x) return -1;
+ RESOLVE(HidD_GetHidGuid);
RESOLVE(HidD_GetAttributes);
RESOLVE(HidD_GetSerialNumberString);
RESOLVE(HidD_GetManufacturerString);
@@ -250,6 +287,29 @@ static int lookup_functions()
else
return -1;
+ cfgmgr32_lib_handle = LoadLibraryA("cfgmgr32.dll");
+ if (cfgmgr32_lib_handle) {
+#if defined(__GNUC__)
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wcast-function-type"
+#endif
+#define RESOLVE(x) x = (x##_)GetProcAddress(cfgmgr32_lib_handle, #x);
+ RESOLVE(CM_Locate_DevNodeW);
+ RESOLVE(CM_Get_Parent);
+ RESOLVE(CM_Get_DevNode_PropertyW);
+ RESOLVE(CM_Get_Device_Interface_PropertyW);
+#undef RESOLVE
+#if defined(__GNUC__)
+# pragma GCC diagnostic pop
+#endif
+ }
+ else {
+ CM_Locate_DevNodeW = NULL;
+ CM_Get_Parent = NULL;
+ CM_Get_DevNode_PropertyW = NULL;
+ CM_Get_Device_Interface_PropertyW = NULL;
+ }
+
return 0;
}
#endif
@@ -301,19 +361,232 @@ int HID_API_EXPORT hid_exit(void)
if (lib_handle)
FreeLibrary(lib_handle);
lib_handle = NULL;
+ if (cfgmgr32_lib_handle)
+ FreeLibrary(cfgmgr32_lib_handle);
+ cfgmgr32_lib_handle = NULL;
initialized = FALSE;
#endif
return 0;
}
+static void hid_internal_get_ble_info(struct hid_device_info* dev, DEVINST dev_node)
+{
+ ULONG len;
+ CONFIGRET cr;
+ DEVPROPTYPE property_type;
+
+ static DEVPROPKEY DEVPKEY_NAME = { { 0xb725f130, 0x47ef, 0x101a, 0xa5, 0xf1, 0x02, 0x60, 0x8c, 0x9e, 0xeb, 0xac }, 10 }; // DEVPROP_TYPE_STRING
+ static DEVPROPKEY PKEY_DeviceInterface_Bluetooth_DeviceAddress = { { 0x2BD67D8B, 0x8BEB, 0x48D5, 0x87, 0xE0, 0x6C, 0xDA, 0x34, 0x28, 0x04, 0x0A }, 1 }; // DEVPROP_TYPE_STRING
+ static DEVPROPKEY PKEY_DeviceInterface_Bluetooth_Manufacturer = { { 0x2BD67D8B, 0x8BEB, 0x48D5, 0x87, 0xE0, 0x6C, 0xDA, 0x34, 0x28, 0x04, 0x0A }, 4 }; // DEVPROP_TYPE_STRING
+
+ /* Manufacturer String */
+ len = 0;
+ cr = CM_Get_DevNode_PropertyW(dev_node, &PKEY_DeviceInterface_Bluetooth_Manufacturer, &property_type, NULL, &len, 0);
+ if (cr == CR_BUFFER_SMALL && property_type == DEVPROP_TYPE_STRING) {
+ free(dev->manufacturer_string);
+ dev->manufacturer_string = (wchar_t*)calloc(len, sizeof(BYTE));
+ CM_Get_DevNode_PropertyW(dev_node, &PKEY_DeviceInterface_Bluetooth_Manufacturer, &property_type, (PBYTE)dev->manufacturer_string, &len, 0);
+ }
+
+ /* Serial Number String (MAC Address) */
+ len = 0;
+ cr = CM_Get_DevNode_PropertyW(dev_node, &PKEY_DeviceInterface_Bluetooth_DeviceAddress, &property_type, NULL, &len, 0);
+ if (cr == CR_BUFFER_SMALL && property_type == DEVPROP_TYPE_STRING) {
+ free(dev->serial_number);
+ dev->serial_number = (wchar_t*)calloc(len, sizeof(BYTE));
+ CM_Get_DevNode_PropertyW(dev_node, &PKEY_DeviceInterface_Bluetooth_DeviceAddress, &property_type, (PBYTE)dev->serial_number, &len, 0);
+ }
+
+ /* Get devnode grandparent to reach out Bluetooth LE device node */
+ cr = CM_Get_Parent(&dev_node, dev_node, 0);
+ if (cr != CR_SUCCESS)
+ return;
+
+ /* Product String */
+ len = 0;
+ cr = CM_Get_DevNode_PropertyW(dev_node, &DEVPKEY_NAME, &property_type, NULL, &len, 0);
+ if (cr == CR_BUFFER_SMALL && property_type == DEVPROP_TYPE_STRING) {
+ free(dev->product_string);
+ dev->product_string = (wchar_t*)calloc(len, sizeof(BYTE));
+ CM_Get_DevNode_PropertyW(dev_node, &DEVPKEY_NAME, &property_type, (PBYTE)dev->product_string, &len, 0);
+ }
+}
+
+static void hid_internal_get_info(struct hid_device_info* dev)
+{
+ const char *tmp = NULL;
+ wchar_t *interface_path = NULL, *device_id = NULL, *compatible_ids = NULL;
+ mbstate_t state;
+ ULONG len;
+ CONFIGRET cr;
+ DEVPROPTYPE property_type;
+ DEVINST dev_node;
+
+ static DEVPROPKEY DEVPKEY_Device_InstanceId = { { 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57 }, 256 }; // DEVPROP_TYPE_STRING
+ static DEVPROPKEY DEVPKEY_Device_CompatibleIds = { { 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0}, 4 }; // DEVPROP_TYPE_STRING_LIST
+
+ if (!CM_Get_Device_Interface_PropertyW ||
+ !CM_Locate_DevNodeW ||
+ !CM_Get_Parent ||
+ !CM_Get_DevNode_PropertyW)
+ goto end;
+
+ tmp = dev->path;
+
+ len = (ULONG)strlen(tmp);
+ interface_path = (wchar_t*)calloc(len + 1, sizeof(wchar_t));
+ memset(&state, 0, sizeof(state));
+
+ if (mbsrtowcs(interface_path, &tmp, len, &state) == (size_t)-1)
+ goto end;
+
+ /* Get the device id from interface path */
+ len = 0;
+ cr = CM_Get_Device_Interface_PropertyW(interface_path, &DEVPKEY_Device_InstanceId, &property_type, NULL, &len, 0);
+ if (cr == CR_BUFFER_SMALL && property_type == DEVPROP_TYPE_STRING) {
+ device_id = (wchar_t*)calloc(len, sizeof(BYTE));
+ cr = CM_Get_Device_Interface_PropertyW(interface_path, &DEVPKEY_Device_InstanceId, &property_type, (PBYTE)device_id, &len, 0);
+ }
+ if (cr != CR_SUCCESS)
+ goto end;
+
+ /* Open devnode from device id */
+ cr = CM_Locate_DevNodeW(&dev_node, (DEVINSTID_W)device_id, CM_LOCATE_DEVNODE_NORMAL);
+ if (cr != CR_SUCCESS)
+ goto end;
+
+ /* Get devnode parent */
+ cr = CM_Get_Parent(&dev_node, dev_node, 0);
+ if (cr != CR_SUCCESS)
+ goto end;
+
+ /* Get the compatible ids from parent devnode */
+ len = 0;
+ cr = CM_Get_DevNode_PropertyW(dev_node, &DEVPKEY_Device_CompatibleIds, &property_type, NULL, &len, 0);
+ if (cr == CR_BUFFER_SMALL && property_type == DEVPROP_TYPE_STRING_LIST) {
+ compatible_ids = (wchar_t*)calloc(len, sizeof(BYTE));
+ cr = CM_Get_DevNode_PropertyW(dev_node, &DEVPKEY_Device_CompatibleIds, &property_type, (PBYTE)compatible_ids, &len, 0);
+ }
+ if (cr != CR_SUCCESS)
+ goto end;
+
+ /* Now we can parse parent's compatible IDs to find out the device bus type */
+ for (wchar_t* compatible_id = compatible_ids; *compatible_id; compatible_id += wcslen(compatible_id) + 1) {
+ /* Normalize to upper case */
+ for (wchar_t* p = compatible_id; *p; ++p) *p = towupper(*p);
+
+ /* Bluetooth LE devices */
+ if (wcsstr(compatible_id, L"BTHLEDEVICE") != NULL) {
+ /* HidD_GetProductString/HidD_GetManufacturerString/HidD_GetSerialNumberString is not working for BLE HID devices
+ Request this info via dev node properties instead.
+ https://docs.microsoft.com/answers/questions/401236/hidd-getproductstring-with-ble-hid-device.html */
+ hid_internal_get_ble_info(dev, dev_node);
+ break;
+ }
+ }
+end:
+ free(interface_path);
+ free(device_id);
+ free(compatible_ids);
+}
+
+static struct hid_device_info *hid_get_device_info(const char *path, HANDLE handle)
+{
+ struct hid_device_info *dev = NULL; /* return object */
+
+ BOOL res;
+ HIDD_ATTRIBUTES attrib;
+ PHIDP_PREPARSED_DATA pp_data = NULL;
+ HIDP_CAPS caps;
+
+ #define WSTR_LEN 512
+ wchar_t wstr[WSTR_LEN]; /* TODO: Determine Size */
+
+ /* Create the record. */
+ dev = (struct hid_device_info*)calloc(1, sizeof(struct hid_device_info));
+
+ /* Fill out the record */
+ dev->next = NULL;
+
+ if (path) {
+ size_t len = strlen(path);
+ dev->path = (char*)calloc(len + 1, sizeof(char));
+ memcpy(dev->path, path, len + 1);
+ }
+ else
+ dev->path = NULL;
+
+ attrib.Size = sizeof(HIDD_ATTRIBUTES);
+ res = HidD_GetAttributes(handle, &attrib);
+ if (res) {
+ /* VID/PID */
+ dev->vendor_id = attrib.VendorID;
+ dev->product_id = attrib.ProductID;
+
+ /* Release Number */
+ dev->release_number = attrib.VersionNumber;
+ }
+
+ /* Get the Usage Page and Usage for this device. */
+ res = HidD_GetPreparsedData(handle, &pp_data);
+ if (res) {
+ NTSTATUS nt_res = HidP_GetCaps(pp_data, &caps);
+ if (nt_res == HIDP_STATUS_SUCCESS) {
+ dev->usage_page = caps.UsagePage;
+ dev->usage = caps.Usage;
+ }
+
+ HidD_FreePreparsedData(pp_data);
+ }
+
+ /* Serial Number */
+ wstr[0] = L'\0';
+ res = HidD_GetSerialNumberString(handle, wstr, sizeof(wstr));
+ wstr[WSTR_LEN - 1] = L'\0';
+ dev->serial_number = _wcsdup(wstr);
+
+ /* Manufacturer String */
+ wstr[0] = L'\0';
+ res = HidD_GetManufacturerString(handle, wstr, sizeof(wstr));
+ wstr[WSTR_LEN - 1] = L'\0';
+ dev->manufacturer_string = _wcsdup(wstr);
+
+ /* Product String */
+ wstr[0] = L'\0';
+ res = HidD_GetProductString(handle, wstr, sizeof(wstr));
+ wstr[WSTR_LEN - 1] = L'\0';
+ dev->product_string = _wcsdup(wstr);
+
+ /* Interface Number. It can sometimes be parsed out of the path
+ on Windows if a device has multiple interfaces. See
+ https://docs.microsoft.com/windows-hardware/drivers/hid/hidclass-hardware-ids-for-top-level-collections
+ or search for "HIDClass Hardware IDs for Top-Level Collections" at Microsoft Docs. If it's not
+ in the path, it's set to -1. */
+ dev->interface_number = -1;
+ if (dev->path) {
+ char* interface_component = strstr(dev->path, "&mi_");
+ if (interface_component) {
+ char* hex_str = interface_component + 4;
+ char* endptr = NULL;
+ dev->interface_number = strtol(hex_str, &endptr, 16);
+ if (endptr == hex_str) {
+ /* The parsing failed. Set interface_number to -1. */
+ dev->interface_number = -1;
+ }
+ }
+ }
+
+ hid_internal_get_info(dev);
+
+ return dev;
+}
+
struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id)
{
BOOL res;
struct hid_device_info *root = NULL; /* return object */
struct hid_device_info *cur_dev = NULL;
-
- /* Hard-coded GUID retreived by HidD_GetHidGuid */
- GUID InterfaceClassGuid = {0x4d1e55b2, 0xf16f, 0x11cf, {0x88, 0xcb, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30} };
+ GUID interface_class_guid;
/* Windows objects for interacting with the driver. */
SP_DEVINFO_DATA devinfo_data;
@@ -326,27 +599,31 @@ struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned shor
if (hid_init() < 0)
return NULL;
+ /* Retrieve HID Interface Class GUID
+ https://docs.microsoft.com/windows-hardware/drivers/install/guid-devinterface-hid */
+ HidD_GetHidGuid(&interface_class_guid);
+
/* Initialize the Windows objects. */
memset(&devinfo_data, 0x0, sizeof(devinfo_data));
devinfo_data.cbSize = sizeof(SP_DEVINFO_DATA);
device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
/* Get information for all the devices belonging to the HID class. */
- device_info_set = SetupDiGetClassDevsA(&InterfaceClassGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
-
+ device_info_set = SetupDiGetClassDevsA(&interface_class_guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
+
/* Iterate over each device in the HID class, looking for the right one. */
-
+
for (;;) {
- HANDLE write_handle = INVALID_HANDLE_VALUE;
+ HANDLE read_handle = INVALID_HANDLE_VALUE;
DWORD required_size = 0;
HIDD_ATTRIBUTES attrib;
res = SetupDiEnumDeviceInterfaces(device_info_set,
NULL,
- &InterfaceClassGuid,
+ &interface_class_guid,
device_index,
&device_interface_data);
-
+
if (!res) {
/* A return of FALSE from this function means that
there are no more devices. */
@@ -398,20 +675,19 @@ struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned shor
//wprintf(L"HandleName: %s\n", device_interface_detail_data->DevicePath);
- /* Open a handle to the device */
- write_handle = open_device(device_interface_detail_data->DevicePath, FALSE);
+ /* Open read-only handle to the device */
+ read_handle = open_device(device_interface_detail_data->DevicePath, FALSE);
- /* Check validity of write_handle. */
- if (write_handle == INVALID_HANDLE_VALUE) {
+ /* Check validity of read_handle. */
+ if (read_handle == INVALID_HANDLE_VALUE) {
/* Unable to open the device. */
//register_error(dev, "CreateFile");
- goto cont_close;
- }
-
+ goto cont;
+ }
/* Get the Vendor ID and Product ID for this device. */
attrib.Size = sizeof(HIDD_ATTRIBUTES);
- HidD_GetAttributes(write_handle, &attrib);
+ HidD_GetAttributes(read_handle, &attrib);
//wprintf(L"Product/Vendor: %x %x\n", attrib.ProductID, attrib.VendorID);
/* Check the VID/PID to see if we should add this
@@ -419,17 +695,13 @@ struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned shor
if ((vendor_id == 0x0 || attrib.VendorID == vendor_id) &&
(product_id == 0x0 || attrib.ProductID == product_id)) {
- #define WSTR_LEN 512
- const char *str;
- struct hid_device_info *tmp;
- PHIDP_PREPARSED_DATA pp_data = NULL;
- HIDP_CAPS caps;
- NTSTATUS nt_res;
- wchar_t wstr[WSTR_LEN]; /* TODO: Determine Size */
- size_t len;
-
/* VID/PID match. Create the record. */
- tmp = (struct hid_device_info*) calloc(1, sizeof(struct hid_device_info));
+ struct hid_device_info *tmp = hid_get_device_info(device_interface_detail_data->DevicePath, read_handle);
+
+ if (tmp == NULL) {
+ goto cont_close;
+ }
+
if (cur_dev) {
cur_dev->next = tmp;
}
@@ -437,84 +709,10 @@ struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned shor
root = tmp;
}
cur_dev = tmp;
-
- /* Get the Usage Page and Usage for this device. */
- res = HidD_GetPreparsedData(write_handle, &pp_data);
- if (res) {
- nt_res = HidP_GetCaps(pp_data, &caps);
- if (nt_res == HIDP_STATUS_SUCCESS) {
- cur_dev->usage_page = caps.UsagePage;
- cur_dev->usage = caps.Usage;
- }
-
- HidD_FreePreparsedData(pp_data);
- }
-
- /* Fill out the record */
- cur_dev->next = NULL;
- str = device_interface_detail_data->DevicePath;
- if (str) {
- len = strlen(str);
- cur_dev->path = (char*) calloc(len+1, sizeof(char));
- strncpy(cur_dev->path, str, len+1);
- cur_dev->path[len] = '\0';
- }
- else
- cur_dev->path = NULL;
-
- /* Serial Number */
- wstr[0]= 0x0000;
- res = HidD_GetSerialNumberString(write_handle, wstr, sizeof(wstr));
- wstr[WSTR_LEN-1] = 0x0000;
- if (res) {
- cur_dev->serial_number = _wcsdup(wstr);
- }
-
- /* Manufacturer String */
- wstr[0]= 0x0000;
- res = HidD_GetManufacturerString(write_handle, wstr, sizeof(wstr));
- wstr[WSTR_LEN-1] = 0x0000;
- if (res) {
- cur_dev->manufacturer_string = _wcsdup(wstr);
- }
-
- /* Product String */
- wstr[0]= 0x0000;
- res = HidD_GetProductString(write_handle, wstr, sizeof(wstr));
- wstr[WSTR_LEN-1] = 0x0000;
- if (res) {
- cur_dev->product_string = _wcsdup(wstr);
- }
-
- /* VID/PID */
- cur_dev->vendor_id = attrib.VendorID;
- cur_dev->product_id = attrib.ProductID;
-
- /* Release Number */
- cur_dev->release_number = attrib.VersionNumber;
-
- /* Interface Number. It can sometimes be parsed out of the path
- on Windows if a device has multiple interfaces. See
- http://msdn.microsoft.com/en-us/windows/hardware/gg487473 or
- search for "Hardware IDs for HID Devices" at MSDN. If it's not
- in the path, it's set to -1. */
- cur_dev->interface_number = -1;
- if (cur_dev->path) {
- char *interface_component = strstr(cur_dev->path, "&mi_");
- if (interface_component) {
- char *hex_str = interface_component + 4;
- char *endptr = NULL;
- cur_dev->interface_number = strtol(hex_str, &endptr, 16);
- if (endptr == hex_str) {
- /* The parsing failed. Set interface_number to -1. */
- cur_dev->interface_number = -1;
- }
- }
- }
}
cont_close:
- CloseHandle(write_handle);
+ CloseHandle(read_handle);
cont:
/* We no longer need the detail data. It can be freed */
free(device_interface_detail_data);
@@ -527,7 +725,6 @@ struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned shor
SetupDiDestroyDeviceInfoList(device_info_set);
return root;
-
}
void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs)
@@ -552,7 +749,7 @@ HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsi
struct hid_device_info *devs, *cur_dev;
const char *path_to_open = NULL;
hid_device *handle = NULL;
-
+
devs = hid_enumerate(vendor_id, product_id);
cur_dev = devs;
while (cur_dev) {
@@ -578,7 +775,7 @@ HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsi
}
hid_free_enumeration(devs);
-
+
return handle;
}
@@ -631,7 +828,7 @@ HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path)
}
nt_res = HidP_GetCaps(pp_data, &caps);
if (nt_res != HIDP_STATUS_SUCCESS) {
- register_error(dev, "HidP_GetCaps");
+ register_error(dev, "HidP_GetCaps");
goto err_pp_data;
}
dev->output_report_length = caps.OutputReportByteLength;
@@ -641,11 +838,13 @@ HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path)
dev->read_buf = (char*) malloc(dev->input_report_length);
+ dev->device_info = hid_get_device_info(path, dev->device_handle);
+
return dev;
err_pp_data:
HidD_FreePreparsedData(pp_data);
-err:
+err:
free_hid_device(dev);
return NULL;
}
@@ -683,7 +882,7 @@ int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *
}
res = WriteFile(dev->device_handle, buf, (DWORD) length, NULL, &dev->write_ol);
-
+
if (!res) {
if (GetLastError() != ERROR_IO_PENDING) {
/* WriteFile() failed. Return error. */
@@ -736,7 +935,7 @@ int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char
memset(dev->read_buf, 0, dev->input_report_length);
ResetEvent(ev);
res = ReadFile(dev->device_handle, dev->read_buf, (DWORD) dev->input_report_length, &bytes_read, &dev->ol);
-
+
if (!res) {
if (GetLastError() != ERROR_IO_PENDING) {
/* ReadFile() has failed.
@@ -745,11 +944,11 @@ int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char
dev->read_pending = FALSE;
goto end_of_function;
}
- overlapped = TRUE;
- }
+ overlapped = TRUE;
+ }
}
else {
- overlapped = TRUE;
+ overlapped = TRUE;
}
if (overlapped) {
@@ -787,13 +986,13 @@ int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char
memcpy(data, dev->read_buf, copy_len);
}
}
-
+
end_of_function:
if (!res) {
register_error(dev, "GetOverlappedResult");
return -1;
}
-
+
return (int) copy_len;
}
@@ -841,25 +1040,16 @@ int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *dev, const u
return (int) length;
}
-
-int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length)
+static int hid_get_report(hid_device *dev, DWORD report_type, unsigned char *data, size_t length)
{
BOOL res;
-#if 0
- res = HidD_GetFeature(dev->device_handle, data, length);
- if (!res) {
- register_error(dev, "HidD_GetFeature");
- return -1;
- }
- return 0; /* HidD_GetFeature() doesn't give us an actual length, unfortunately */
-#else
- DWORD bytes_returned;
+ DWORD bytes_returned = 0;
OVERLAPPED ol;
memset(&ol, 0, sizeof(ol));
res = DeviceIoControl(dev->device_handle,
- IOCTL_HID_GET_FEATURE,
+ report_type,
data, (DWORD) length,
data, (DWORD) length,
&bytes_returned, &ol);
@@ -867,7 +1057,7 @@ int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *dev, unsigned
if (!res) {
if (GetLastError() != ERROR_IO_PENDING) {
/* DeviceIoControl() failed. Return error. */
- register_error(dev, "Send Feature Report DeviceIoControl");
+ register_error(dev, "Get Input/Feature Report DeviceIoControl");
return -1;
}
}
@@ -877,56 +1067,30 @@ int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *dev, unsigned
res = GetOverlappedResult(dev->device_handle, &ol, &bytes_returned, TRUE/*wait*/);
if (!res) {
/* The operation failed. */
- register_error(dev, "Send Feature Report GetOverLappedResult");
+ register_error(dev, "Get Input/Feature Report GetOverLappedResult");
return -1;
}
+ /* When numbered reports aren't used,
+ bytes_returned seem to include only what is actually received from the device
+ (not including the first byte with 0, as an indication "no numbered reports"). */
+ if (data[0] == 0x0) {
+ bytes_returned++;
+ }
+
return bytes_returned;
-#endif
}
+int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length)
+{
+ /* We could use HidD_GetFeature() instead, but it doesn't give us an actual length, unfortunately */
+ return hid_get_report(dev, IOCTL_HID_GET_FEATURE, data, length);
+}
int HID_API_EXPORT HID_API_CALL hid_get_input_report(hid_device *dev, unsigned char *data, size_t length)
{
- BOOL res;
-#if 0
- res = HidD_GetInputReport(dev->device_handle, data, length);
- if (!res) {
- register_error(dev, "HidD_GetInputReport");
- return -1;
- }
- return length;
-#else
- DWORD bytes_returned;
-
- OVERLAPPED ol;
- memset(&ol, 0, sizeof(ol));
-
- res = DeviceIoControl(dev->device_handle,
- IOCTL_HID_GET_INPUT_REPORT,
- data, (DWORD) length,
- data, (DWORD) length,
- &bytes_returned, &ol);
-
- if (!res) {
- if (GetLastError() != ERROR_IO_PENDING) {
- /* DeviceIoControl() failed. Return error. */
- register_error(dev, "Send Input Report DeviceIoControl");
- return -1;
- }
- }
-
- /* Wait here until the write is done. This makes
- hid_get_feature_report() synchronous. */
- res = GetOverlappedResult(dev->device_handle, &ol, &bytes_returned, TRUE/*wait*/);
- if (!res) {
- /* The operation failed. */
- register_error(dev, "Send Input Report GetOverLappedResult");
- return -1;
- }
-
- return bytes_returned;
-#endif
+ /* We could use HidD_GetInputReport() instead, but it doesn't give us an actual length, unfortunately */
+ return hid_get_report(dev, IOCTL_HID_GET_INPUT_REPORT, data, length);
}
void HID_API_EXPORT HID_API_CALL hid_close(hid_device *dev)
@@ -939,39 +1103,33 @@ void HID_API_EXPORT HID_API_CALL hid_close(hid_device *dev)
int HID_API_EXPORT_CALL HID_API_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen)
{
- BOOL res;
-
- res = HidD_GetManufacturerString(dev->device_handle, string, sizeof(wchar_t) * (DWORD) MIN(maxlen, MAX_STRING_WCHARS));
- if (!res) {
- register_error(dev, "HidD_GetManufacturerString");
+ if (!dev->device_info || !string || !maxlen)
return -1;
- }
+
+ wcsncpy(string, dev->device_info->manufacturer_string, maxlen);
+ string[maxlen] = L'\0';
return 0;
}
int HID_API_EXPORT_CALL HID_API_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen)
{
- BOOL res;
-
- res = HidD_GetProductString(dev->device_handle, string, sizeof(wchar_t) * (DWORD) MIN(maxlen, MAX_STRING_WCHARS));
- if (!res) {
- register_error(dev, "HidD_GetProductString");
+ if (!dev->device_info || !string || !maxlen)
return -1;
- }
+
+ wcsncpy(string, dev->device_info->product_string, maxlen);
+ string[maxlen] = L'\0';
return 0;
}
int HID_API_EXPORT_CALL HID_API_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen)
{
- BOOL res;
-
- res = HidD_GetSerialNumberString(dev->device_handle, string, sizeof(wchar_t) * (DWORD) MIN(maxlen, MAX_STRING_WCHARS));
- if (!res) {
- register_error(dev, "HidD_GetSerialNumberString");
+ if (!dev->device_info || !string || !maxlen)
return -1;
- }
+
+ wcsncpy(string, dev->device_info->serial_number, maxlen);
+ string[maxlen] = L'\0';
return 0;
}
@@ -1006,7 +1164,7 @@ HID_API_EXPORT const wchar_t * HID_API_CALL hid_error(hid_device *dev)
/*#define PICPGM*/
/*#define S11*/
#define P32
-#ifdef S11
+#ifdef S11
unsigned short VendorID = 0xa0a0;
unsigned short ProductID = 0x0001;
#endif
@@ -1036,7 +1194,7 @@ int __cdecl main(int argc, char* argv[])
memset(buf,0x00,sizeof(buf));
buf[0] = 0;
buf[1] = 0x81;
-
+
/* Open the device. */
int handle = open(VendorID, ProductID, L"12345");
diff --git a/custom/dependencies/hidapi/windows/hidapi.vcxproj.filters b/custom/dependencies/hidapi/windows/hidapi.vcxproj.filters
new file mode 100644
index 000000000..af3a78a3a
--- /dev/null
+++ b/custom/dependencies/hidapi/windows/hidapi.vcxproj.filters
@@ -0,0 +1,27 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hpp;hxx;hm;inl;inc;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav
+
+
+
+
+ Source Files
+
+
+
+
+ Header Files
+
+
+
\ No newline at end of file
diff --git a/custom/dependencies/hidapi/windows/hidtest.vcxproj.filters b/custom/dependencies/hidapi/windows/hidtest.vcxproj.filters
new file mode 100644
index 000000000..98b7e73e2
--- /dev/null
+++ b/custom/dependencies/hidapi/windows/hidtest.vcxproj.filters
@@ -0,0 +1,22 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hpp;hxx;hm;inl;inc;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav
+
+
+
+
+ Source Files
+
+
+