Problem: One of the shortcomings of the current implementation of
libhid is that it does not handle multiple devices correctly. For
example, with
two identical devices on the USB bus with the same vendor and product
id's, libhid returns a handle to the first successful match. I do not
believe that
this was the intended behavior of the package.
Solution:
I have attached a patch to hid_opening.c that should fix the
problem. It basically keeps a list of currently open device/interface
pairs, and keeps searching
for a new device/interface before looking for a match. Before
returning from hid_open for hid_force_open, it adds the device to the
list of open
device/interface pairs.
This implementation does not work for different processes and is not
currently thread safe. However, libhid has these same issues.
Enjoy,
Warren
--- hid_opening.c 2007-11-28 07:39:08.000000000 -0500
+++ hid_opening.c.new 2008-01-22 10:02:19.000000000 -0500
@@ -15,6 +15,54 @@
USB_MATCH_ALL = USB_MATCH_VENDOR | USB_MATCH_PRODUCT | USB_MATCH_CUSTOM
};
+#define MAX_OPEN_DEVICES 20 // Should be changed to dynmaic
+static struct t_open_hid_device_list {
+ int nDevices; // number of known open devices
+ HIDInterface* hidif[MAX_OPEN_DEVICES];
+} open_hid_device_list = {0,
+ {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}
+ };
+
+static int add_open_device(HIDInterface* hidif)
+{
+ if (open_hid_device_list.nDevices < MAX_OPEN_DEVICES) {
+ open_hid_device_list.hidif[open_hid_device_list.nDevices++] = hidif;
+ return 0;
+ } else {
+ TRACE("open_hid_device_list is full.");
+ return -1;
+ }
+}
+
+static void remove_open_device(HIDInterface* hidif)
+{
+ int i, j;
+ for (i = 0; i < open_hid_device_list.nDevices; i++) {
+ if (hidif == open_hid_device_list.hidif[i]) {
+ for (j = i+1; j < open_hid_device_list.nDevices; j++) {
+ open_hid_device_list.hidif[j-1] = open_hid_device_list.hidif[j];
+ }
+ open_hid_device_list.nDevices--;
+ return;
+ }
+ }
+}
+
+static int hid_previously_matched(struct usb_dev_handle const* dev_h, int
interface)
+{
+ int i;
+ struct usb_device const* usbdev = usb_device((usb_dev_handle*)dev_h);
+
+ for (i = 0; i < open_hid_device_list.nDevices; i++) {
+ if ((interface == open_hid_device_list.hidif[i]->interface) &&
+ (usbdev == open_hid_device_list.hidif[i]->device)) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
static unsigned int hid_compare_usb_device(struct usb_dev_handle const* dev_h,
HIDInterfaceMatcher const* const match)
{
@@ -26,7 +74,7 @@
TRACE("comparing match specifications to USB device...");
struct usb_device const* dev = usb_device((usb_dev_handle*)dev_h);
-
+
TRACE("inspecting vendor ID...");
if (dev->descriptor.idVendor > 0 &&
(dev->descriptor.idVendor & match->vendor_id) == match->vendor_id) {
@@ -83,7 +131,15 @@
usb_dev_handle *usbdev_h = usb_open(usbdev);
if (usbdev_h) {
- usb_claim_interface(usbdev_h, hidif->interface);
+ if (!usb_claim_interface(usbdev_h, hidif->interface)) {
+ TRACE("Could not claim interface %d...\n", hidif->interface);
+ }
+
+ // Make sure we are not considering an already matched device
+ if (hid_previously_matched(usbdev_h, hidif->interface)) {
+ TRACE("match of previously open device/interface...");
+ continue;
+ }
unsigned int flags = hid_compare_usb_device(usbdev_h, match);
if (flags == USB_MATCH_ALL) {
@@ -175,6 +231,9 @@
ret = hid_prepare_interface(hidif);
if (ret != HID_RET_SUCCESS) return ret;
+ TRACE("add open device to list...");
+ add_open_device(hidif);
+
NOTICE("successfully opened USB device %s.", hidif->id);
return HID_RET_SUCCESS;
}
@@ -221,6 +280,9 @@
ret = hid_prepare_interface(hidif);
if (ret != HID_RET_SUCCESS) return ret;
+ TRACE("add open device to list...");
+ add_open_device(hidif);
+
NOTICE("successfully opened USB device %s.", hidif->id);
return HID_RET_SUCCESS;
}
@@ -248,13 +310,16 @@
}
}
else WARNING("attempt to close unopened USB device %s.", hidif->id);
+
+ TRACE("remove hidif from open list...");
+ remove_open_device(hidif);
if (hidif->hid_parser) hid_reset_parser(hidif);
TRACE("freeing memory allocated for HID parser...");
if(hidif->hid_parser) free(hidif->hid_parser);
if(hidif->hid_data) free(hidif->hid_data);
-
+
TRACE("resetting HIDInterface...");
hid_reset_HIDInterface(hidif);
_______________________________________________
libhid-discuss mailing list
[email protected]
http://lists.alioth.debian.org/mailman/listinfo/libhid-discuss