mirror of
https://github.com/RPCS3/hidapi.git
synced 2026-01-31 01:25:21 +01:00
add libusb-specific hid_libusb_wrap_sys_device
Rationale: on Android one must use UsbManager, to access any USB device. As a result, libraries like libusb can only use file descriptors that are provided by UsbManager. libusb has an API to use such file descriptors: hid_libusb_wrap_sys_device. Having hid_libusb_wrap_sys_device currently is the only way to make hidapi work on Android without root access and without custom Android builds. Relevant info: https://github.com/libusb/libusb/pull/830/files
This commit is contained in:
14
.github/workflows/builds.yml
vendored
14
.github/workflows/builds.yml
vendored
@@ -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:
|
||||
@@ -76,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:
|
||||
|
||||
@@ -3,6 +3,7 @@ cmake_minimum_required(VERSION 3.6.3 FATAL_ERROR)
|
||||
add_library(hidapi_libusb
|
||||
${HIDAPI_PUBLIC_HEADERS}
|
||||
hid.c
|
||||
hidapi_libusb.h
|
||||
)
|
||||
target_link_libraries(hidapi_libusb PUBLIC hidapi_include)
|
||||
|
||||
@@ -23,7 +24,7 @@ set_target_properties(hidapi_libusb
|
||||
OUTPUT_NAME "hidapi-libusb"
|
||||
VERSION ${PROJECT_VERSION}
|
||||
SOVERSION ${PROJECT_VERSION_MAJOR}
|
||||
PUBLIC_HEADER "${HIDAPI_PUBLIC_HEADERS}"
|
||||
PUBLIC_HEADER "${HIDAPI_PUBLIC_HEADERS};hidapi_libusb.h"
|
||||
)
|
||||
|
||||
# compatibility with find_package()
|
||||
|
||||
@@ -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
|
||||
|
||||
462
libusb/hid.c
462
libusb/hid.c
@@ -49,7 +49,7 @@
|
||||
#include <iconv.h>
|
||||
#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;
|
||||
int interface_num = intf_desc->bInterfaceNumber;
|
||||
struct hid_device_info *tmp;
|
||||
|
||||
/* 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;
|
||||
/* 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;
|
||||
|
||||
/* Release Number */
|
||||
cur_dev->release_number = desc.bcdDevice;
|
||||
|
||||
/* Interface Number */
|
||||
cur_dev->interface_number = interface_num;
|
||||
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;
|
||||
|
||||
/* 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;
|
||||
|
||||
54
libusb/hidapi_libusb.h
Normal file
54
libusb/hidapi_libusb.h
Normal file
@@ -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 <stdint.h>
|
||||
|
||||
#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
|
||||
Reference in New Issue
Block a user