From 116d34f608b02f4e14668450b158acf5db726f95 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Tue, 5 Oct 2010 12:43:41 +0100 Subject: [PATCH] Windows: add support for filter drivers * precedence is driver > upper filter > lower filter, and defined in struct driver_lookup lookup from set_device_paths() --- libusb/os/windows_usb.c | 152 +++++++++++++++++++++++++++++++----------------- libusb/os/windows_usb.h | 8 +++ 2 files changed, 106 insertions(+), 54 deletions(-) diff --git a/libusb/os/windows_usb.c b/libusb/os/windows_usb.c index b42cea2..e37932a 100644 --- a/libusb/os/windows_usb.c +++ b/libusb/os/windows_usb.c @@ -397,11 +397,25 @@ static int windows_assign_endpoints(struct libusb_device *dev, int iface, int al bool is_api_driver(char* driver, uint8_t api) { uint8_t i; - for (i=0; idevices[j]->bus_number, discdevs->devices[j]->device_address, priv->path); - // Check the service name to know what kind of device we have. - // The service name is really the driver name without ".sys" ("WinUSB", "HidUsb", ...) - // It tells us if we can use WinUSB, if we have a composite device, and the API to use - if(!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data, SPDRP_SERVICE, - ®_type, (BYTE*)reg_key, MAX_KEY_LENGTH, &size)) { - usbi_err(ctx, "could not retrieve driver information for device %s, skipping: %s", - dev_interface_details->DevicePath, windows_error_str(0)); - break; + // Check the service & filter names to know the API we should use + for (k=0; k<3; k++) { + if (SetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, lookup[k].reg_prop, + ®_type, (BYTE*)lookup[k].list, MAX_KEY_LENGTH, &size)) { + // Turn the REG_SZ SPDRP_SERVICE into REG_MULTI_SZ + if (lookup[k].reg_prop == SPDRP_SERVICE) { + // our buffers are MAX_KEY_LENGTH+1 so we can overflow if needed + lookup[k].list[safe_strlen(lookup[k].list)+1] = 0; + } + // MULTI_SZ is a pain to work with. Turn it into something much more manageable + // NB: none of the driver names we check against contain LIST_SEPARATOR, + // (currently ';'), so even if an unsuported one does, it's not an issue + for (l=0; (lookup[k].list[l] != 0) || (lookup[k].list[l+1] != 0); l++) { + if (lookup[k].list[l] == 0) { + lookup[k].list[l] = LIST_SEPARATOR; + } + } + upperize(lookup[k].list); + usbi_dbg("%s(s): %s", lookup[k].designation, lookup[k].list); + found = true; + } else { + if (GetLastError() != ERROR_INVALID_DATA) { + usbi_dbg("could not access %s: %s", lookup[k].designation, windows_error_str(0)); + } + lookup[k].list[0] = 0; + } } - usbi_dbg("driver: %s", reg_key); - found = true; - - for (api = 0; apiapib = &usb_api_backend[api]; - switch(api) { - case USB_API_COMPOSITE: - set_composite_device(ctx, dev_info_data.DevInst, priv); - break; - case USB_API_HID: - safe_free(priv->hid); - priv->hid = calloc(1, sizeof(struct hid_device_priv)); - if (priv->hid == NULL) { - usbi_err(ctx, "could not allocate HID data for %s, skipping", - dev_interface_details->DevicePath); - priv->apib = &usb_api_backend[USB_API_UNSUPPORTED]; - safe_free(priv->path); - } else { - set_hid_device(ctx, priv); - } - break; - default: - // For other devices, the first interface is the same as the device - priv->usb_interface[0].path = malloc(safe_strlen(priv->path)+1); - if (priv->usb_interface[0].path != NULL) { - safe_strcpy(priv->usb_interface[0].path, safe_strlen(priv->path)+1, priv->path); - } - // The following is needed if we want to API calls to work for both simple - // and composite devices, as - for(k=0; kusb_interface[k].apib = &usb_api_backend[api]; - } + for (api=0; api= 3) continue; + priv->apib = &usb_api_backend[api]; + switch(api) { + case USB_API_COMPOSITE: + set_composite_device(ctx, dev_info_data.DevInst, priv); + break; + case USB_API_HID: + safe_free(priv->hid); + priv->hid = calloc(1, sizeof(struct hid_device_priv)); + if (priv->hid == NULL) { + usbi_err(ctx, "could not allocate HID data for %s, skipping", + dev_interface_details->DevicePath); + priv->apib = &usb_api_backend[USB_API_UNSUPPORTED]; + safe_free(priv->path); + } else { + set_hid_device(ctx, priv); + } + break; + default: + // For other devices, the first interface is the same as the device + priv->usb_interface[0].path = malloc(safe_strlen(priv->path)+1); + if (priv->usb_interface[0].path != NULL) { + safe_strcpy(priv->usb_interface[0].path, safe_strlen(priv->path)+1, priv->path); + } + // The following is needed if we want to API calls to work for both simple + // and composite devices, as + for(k=0; kusb_interface[k].apib = &usb_api_backend[api]; + } + break; + } } break; } @@ -1598,7 +1637,7 @@ static void windows_exit(void) if (WaitForSingleObject(semaphore, INFINITE) != WAIT_OBJECT_0) { CloseHandle(semaphore); return; - } + } // Only works if exits and inits are balanced exactly if (--concurrent_usage < 0) { // Last exit @@ -2282,12 +2321,14 @@ static int unsupported_copy_transfer_data(struct usbi_transfer *itransfer, uint3 PRINT_UNSUPPORTED_API(copy_transfer_data); } -const char* composite_driver_names[] = {"usbccgp"}; -const char* winusb_driver_names[] = {"WinUSB"}; -const char* hid_driver_names[] = {"HidUsb", "mouhid", "kbdhid"}; +// These names must be uppercase +const char* composite_driver_names[] = {"USBCCGP"}; +const char* winusb_driver_names[] = {"WINUSB"}; +const char* hid_driver_names[] = {"HIDUSB", "MOUHID", "KBDHID"}; const struct windows_usb_api_backend usb_api_backend[USB_API_MAX] = { { USB_API_UNSUPPORTED, + "Unsupported API", &CLASS_GUID_UNSUPPORTED, NULL, 0, @@ -2308,9 +2349,10 @@ const struct windows_usb_api_backend usb_api_backend[USB_API_MAX] = { unsupported_copy_transfer_data, }, { USB_API_COMPOSITE, + "Composite API", &CLASS_GUID_COMPOSITE, composite_driver_names, - 1, + sizeof(composite_driver_names)/sizeof(composite_driver_names[0]), composite_init, composite_exit, composite_open, @@ -2328,9 +2370,10 @@ const struct windows_usb_api_backend usb_api_backend[USB_API_MAX] = { composite_copy_transfer_data, }, { USB_API_WINUSB, + "WinUSB API", &CLASS_GUID_LIBUSB_WINUSB, winusb_driver_names, - 1, + sizeof(winusb_driver_names)/sizeof(winusb_driver_names[0]), winusb_init, winusb_exit, winusb_open, @@ -2348,9 +2391,10 @@ const struct windows_usb_api_backend usb_api_backend[USB_API_MAX] = { winusb_copy_transfer_data, }, { USB_API_HID, + "HID API", &CLASS_GUID_HID, hid_driver_names, - 3, + sizeof(hid_driver_names)/sizeof(hid_driver_names[0]), hid_init, hid_exit, hid_open, diff --git a/libusb/os/windows_usb.h b/libusb/os/windows_usb.h index c2b38bb..dc90a64 100644 --- a/libusb/os/windows_usb.h +++ b/libusb/os/windows_usb.h @@ -97,6 +97,7 @@ inline void upperize(char* str) { #define MAX_TIMER_SEMAPHORES 128 #define TIMER_REQUEST_RETRY_MS 100 #define ERR_BUFFER_SIZE 256 +#define LIST_SEPARATOR ';' // Handle code for HID interface that have been claimed ("dibs") #define INTERFACE_CLAIMED ((HANDLE)(intptr_t)0xD1B5) @@ -129,6 +130,7 @@ const GUID CLASS_GUID_COMPOSITE = { 0x36FC9E60, 0xC465, 0x11cF, {0x80, 0x56, struct windows_usb_api_backend { const uint8_t id; + const char* designation; const GUID *class_guid; // The Class GUID (for fallback in case the driver name cannot be read) const char **driver_name_list; // Driver name, without .sys, e.g. "usbccgp" const uint8_t nb_driver_names; @@ -327,6 +329,12 @@ struct windows_transfer_priv { size_t hid_expected_size; }; +// used to match a device driver (including filter drivers) against a supported API +struct driver_lookup { + char list[MAX_KEY_LENGTH+1];// REG_MULTI_SZ list of services (driver) names + const DWORD reg_prop; // SPDRP registry key to use to retreive list + const char* designation; // internal designation (for debug output) +}; /* * API macros - from libusb-win32 1.x -- 2.7.4