From 2908c3cefa0c6caf93b5111a8fd15563cf9985b9 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Mon, 15 Feb 2010 01:27:30 +0000 Subject: new winusb automated driver installation branch --- examples/lsusb.c | 10 +++ libusb/os/driver_install.c | 147 +++++++++++++++++++++++++++++++++++++++++++++ libusb/os/driver_install.h | 17 ++++++ libusb/os/windows_usb.c | 34 ++++++----- libusb/os/windows_usb.h | 24 +++----- libusb_2008.sln | 32 +++++++--- 6 files changed, 224 insertions(+), 40 deletions(-) create mode 100644 libusb/os/driver_install.c create mode 100644 libusb/os/driver_install.h diff --git a/examples/lsusb.c b/examples/lsusb.c index 58d58fe..6b815d4 100644 --- a/examples/lsusb.c +++ b/examples/lsusb.c @@ -21,6 +21,7 @@ #include #include +#include static void print_devs(libusb_device **devs) { @@ -50,6 +51,15 @@ main(void) libusb_device **devs; int r; ssize_t cnt; + struct driver_info *drv_info; + + drv_info = list_driverless(); + for (; drv_info != NULL; drv_info = drv_info->next) { + printf("%s\n", drv_info->desc); + printf(" %s\n", drv_info->vid); + printf(" %s\n", drv_info->pid); + printf(" %s\n", drv_info->mi); + } r = libusb_init(NULL); if (r < 0) diff --git a/libusb/os/driver_install.c b/libusb/os/driver_install.c new file mode 100644 index 0000000..3c80901 --- /dev/null +++ b/libusb/os/driver_install.c @@ -0,0 +1,147 @@ +#if defined(_MSC_VER) +#include +#else +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include // for GUID ops. requires libole32.a + +#include "libusbi.h" +#include "windows_usb.h" +#include "driver_install.h" + +char* guid_to_string(const GUID guid) +{ + static char guid_string[MAX_GUID_STRING_LENGTH]; + + sprintf(guid_string, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", + (unsigned int)guid.Data1, guid.Data2, guid.Data3, + guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], + guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]); + return guid_string; +} + +void free_di(struct driver_info *start) +{ + struct driver_info *tmp; + while(start != NULL) { + tmp = start; + start = start->next; + free(tmp); + } +} + +struct driver_info* list_driverless(void) +{ + unsigned i, j; + struct libusb_context *ctx = NULL; + DWORD size, reg_type, install_state; + CONFIGRET r; + HDEVINFO dev_info; + SP_DEVINFO_DATA dev_info_data; + SP_DEVICE_INTERFACE_DETAIL_DATA *dev_interface_details = NULL; + char *sanitized_short = NULL; + char *prefix[3] = {"VID_", "PID_", "MI_"}; +// char *designation[3] = {"VendorID", "ProductID", "InterfaceID"}; + char *token; + char path[MAX_PATH_LENGTH]; + char desc[MAX_DESC_LENGTH]; + struct driver_info *ret = NULL, *cur = NULL, *drv_info; + + // List all connected USB devices + dev_info = SetupDiGetClassDevs(NULL, "USB", NULL, DIGCF_PRESENT|DIGCF_ALLCLASSES); + if (dev_info == INVALID_HANDLE_VALUE) { + return NULL; + } + + // Find the ones that are driverless + for (i = 0; ; i++) + { + safe_free(sanitized_short); + + dev_info_data.cbSize = sizeof(dev_info_data); + if (!SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data)) { + break; + } + + if ( (!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data, SPDRP_INSTALL_STATE, + ®_type, (BYTE*)&install_state, 4, &size)) + && (size != 4) ) { + usbi_warn(ctx, "could not detect installation state of driver for %d: %s", + i, windows_error_str(0)); + continue; + } + if (install_state != InstallStateFailedInstall) { + continue; + } + + if ( (!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data, SPDRP_DEVICEDESC, + ®_type, (BYTE*)desc, MAX_KEY_LENGTH, &size)) ) { + usbi_warn(ctx, "could not read device description for %d: %s", + i, windows_error_str(0)); + continue; + } + + r = CM_Get_Device_ID(dev_info_data.DevInst, path, MAX_PATH_LENGTH, 0); + if (r != CR_SUCCESS) { + usbi_err(ctx, "could not retrieve simple path for device %d: CR error %d", + i, r); + continue; + } + sanitized_short = sanitize_path(path); + if (sanitized_short == NULL) { + usbi_err(ctx, "could not sanitize path for device %d", i); + continue; + } + usbi_dbg("Driverless USB device (%d): %s", i, sanitized_short); +// usbi_dbg(" DeviceName = \"%s\"", desc); + + drv_info = calloc(1, sizeof(struct driver_info)); + if (drv_info == NULL) { + free_di(ret); + return NULL; + } + if (cur == NULL) { + ret = drv_info; + } else { + cur->next = drv_info; + } + cur = drv_info; + + safe_strcpy(drv_info->desc, sizeof(drv_info->desc), desc); + + token = strtok (sanitized_short, "#&"); + while(token != NULL) { + for (j = 0; j < 3; j++) { + if (safe_strncmp(token, prefix[j], strlen(prefix[j])) == 0) { + switch(j) { + case 0: + safe_strcpy(drv_info->vid, sizeof(drv_info->vid), token); + break; + case 1: + safe_strcpy(drv_info->pid, sizeof(drv_info->pid), token); + break; + case 2: + safe_strcpy(drv_info->mi, sizeof(drv_info->mi), token); + break; + default: + usbi_err(ctx, "unexpected case"); + break; + } + } + } + token = strtok (NULL, "#&"); + } + CoCreateGuid(&drv_info->dev_guid); + +// usbi_dbg(" DeviceGUID = \"%s\"", guid_to_string(drv_info->dev_guid)); + } + return ret; +} \ No newline at end of file diff --git a/libusb/os/driver_install.h b/libusb/os/driver_install.h new file mode 100644 index 0000000..f1703b3 --- /dev/null +++ b/libusb/os/driver_install.h @@ -0,0 +1,17 @@ +#pragma once + +#include +#define MAX_DESC_LENGTH 128 + +struct driver_info { + struct driver_info *next; + char desc[MAX_DESC_LENGTH]; + char vid[9]; + char pid[9]; + char mi[6]; + GUID dev_guid; +}; + +struct driver_info *list_driverless(void); +char* guid_to_string(const GUID guid); + diff --git a/libusb/os/windows_usb.c b/libusb/os/windows_usb.c index e48db35..3723239 100644 --- a/libusb/os/windows_usb.c +++ b/libusb/os/windows_usb.c @@ -106,6 +106,18 @@ static int composite_abort_control(struct usbi_transfer *itransfer); static int composite_reset_device(struct libusb_device_handle *dev_handle); static int composite_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size); +// http://msdn.microsoft.com/en-us/library/bb663109.aspx +// http://msdn.microsoft.com/en-us/library/bb663093.aspx +#if !defined(GUID_DEVINTERFACE_USB_HOST_CONTROLLER) +const GUID GUID_DEVINTERFACE_USB_HOST_CONTROLLER = { 0x3ABF6F2D, 0x71C4, 0x462A, {0x8A, 0x92, 0x1E, 0x68, 0x61, 0xE6, 0xAF, 0x27} }; +#endif +#if !defined(GUID_DEVINTERFACE_USB_DEVICE) +const GUID GUID_DEVINTERFACE_USB_DEVICE = { 0xA5DCBF10, 0x6530, 0x11D2, {0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED} }; +#endif +const GUID CLASS_GUID_UNSUPPORTED = { 0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x57, 0xDA} }; +const GUID CLASS_GUID_HID = { 0x745A17A0, 0x74D3, 0x11D0, {0xB6, 0xFE, 0x00, 0xA0, 0xC9, 0x0F, 0x57, 0xDA} }; +const GUID CLASS_GUID_LIBUSB_WINUSB = { 0x78A1C341, 0x4539, 0x11D3, {0xB8, 0x8D, 0x00, 0xC0, 0x4F, 0xAD, 0x51, 0x71} }; +const GUID CLASS_GUID_COMPOSITE = { 0x36FC9E60, 0xC465, 0x11cF, {0x80, 0x56, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} }; // Global variables struct windows_hcd_priv* hcd_root = NULL; @@ -161,24 +173,11 @@ static inline BOOLEAN guid_eq(const GUID *guid1, const GUID *guid2) { return false; } -#if 0 -static char* guid_to_string(const GUID guid) -{ - static char guid_string[MAX_GUID_STRING_LENGTH]; - - sprintf(guid_string, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", - (unsigned int)guid.Data1, guid.Data2, guid.Data3, - guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], - guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]); - return guid_string; -} -#endif - /* * Converts a windows error to human readable string * uses retval as errorcode, or, if 0, use GetLastError() */ -static char *windows_error_str(uint32_t retval) +char *windows_error_str(uint32_t retval) { static char err_string[ERR_BUFFER_SIZE]; @@ -208,7 +207,7 @@ static char err_string[ERR_BUFFER_SIZE]; * Sanitize Microsoft's paths: convert to uppercase, add prefix and fix backslashes. * Return an allocated sanitized string or NULL on error. */ -static char* sanitize_path(const char* path) +char* sanitize_path(const char* path) { const char root_prefix[] = "\\\\.\\"; size_t j, size, root_size; @@ -1001,6 +1000,7 @@ enum libusb_hid_report_type { continue; } CLSIDFromString(guid_string_w, &guid); +//usbi_dbg("GUID: %s", guid_to_string(guid)); // identical device interface GUIDs are not supposed to happen, but are a real possibility // => check and ignore duplicates @@ -1033,7 +1033,7 @@ enum libusb_hid_report_type { dev_interface_details = get_interface_details(ctx, &dev_info, &dev_info_data, guid, i); if (dev_interface_details == NULL) break; - +usbi_dbg("%s", dev_interface_details->DevicePath); // HID devices (and possibly other classes) have an extra indirection // for an USB path we can recognize if (j == HID_DEVICE_INTERFACE_GUID_INDEX) { @@ -1264,6 +1264,8 @@ static int set_device_paths(struct libusb_context *ctx, struct discovered_devs * uint8_t api; bool found; +// list_driverless(ctx); + // TODO (v1.5): MI_## automated driver installation guid = GUID_DEVINTERFACE_USB_DEVICE; for (i = 0; ; i++) diff --git a/libusb/os/windows_usb.h b/libusb/os/windows_usb.h index cd74e22..b11b318 100644 --- a/libusb/os/windows_usb.h +++ b/libusb/os/windows_usb.h @@ -82,6 +82,8 @@ inline void upperize(char* str) { for (i=0; i