diff options
author | Pete Batard <pbatard@gmail.com> | 2010-01-14 01:26:01 +0000 |
---|---|---|
committer | Pete Batard <pbatard@gmail.com> | 2010-01-14 01:26:01 +0000 |
commit | 191930f7007f373144ee7ecfc098eb390a33265d (patch) | |
tree | c24f780f70f0cd0c7add5d967b0406e7c4101ee2 | |
parent | 0cf1a367fabb80de559b7bb3e99ee541e59510ae (diff) | |
download | libusb-191930f7007f373144ee7ecfc098eb390a33265d.tar.gz |
svn r42:
- code cleanup
- device reset improvement (tentative)
- inquiry request for Mass Storage in xusb.c
-rw-r--r-- | examples/xusb.c | 43 | ||||
-rw-r--r-- | libusb/os/windows_compat.c | 25 | ||||
-rw-r--r-- | libusb/os/windows_usb.c | 254 | ||||
-rw-r--r-- | libusb/os/windows_usb.h | 33 |
4 files changed, 150 insertions, 205 deletions
diff --git a/examples/xusb.c b/examples/xusb.c index d2124a0..0341d7f 100644 --- a/examples/xusb.c +++ b/examples/xusb.c @@ -134,6 +134,16 @@ int test_mass_storage(libusb_device_handle *handle) unsigned char lun; struct command_block_wrapper cbw; struct command_status_wrapper csw; + uint8_t buffer[512]; + if (buffer == NULL) { + perr("failed to allocate mass storage test buffer\n"); + return -1; + } + + // This reset doesn't seem to work... + printf("Resetting device...\n"); + CALL_CHECK(libusb_reset_device(handle)); + printf("Sending Mass Storage Reset...\n"); CALL_CHECK(libusb_control_transfer(handle, LIBUSB_ENDPOINT_OUT|LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE, BOMS_RESET, 0, 0, NULL, 0, 1000)); @@ -152,15 +162,31 @@ int test_mass_storage(libusb_device_handle *handle) cbw.bCBWLUN = 0; cbw.bCBWCBLength = 1; - CALL_CHECK(libusb_bulk_transfer(handle, 0x01, (unsigned char*)&cbw, 16, &size, 1000)); + CALL_CHECK(libusb_bulk_transfer(handle, 0x01, (unsigned char*)&cbw, 16, &size, 1000)); printf("sent %d bytes\n", size); - CALL_CHECK(libusb_bulk_transfer(handle, 0x81, (unsigned char*)&csw, 13, &size, 1000)); + CALL_CHECK(libusb_bulk_transfer(handle, 0x81, (unsigned char*)&csw, 13, &size, 1000)); printf("received %d bytes\n", size); printf("Tag = %08X\n", csw.dCSWTag); printf("Status = %02X\n", csw.bCSWStatus); - printf("Resetting device...\n"); - CALL_CHECK(libusb_reset_device(handle)); + // Send Inquiry + cbw.dCBWSignature[0] = 'U'; + cbw.dCBWSignature[1] = 'S'; + cbw.dCBWSignature[2] = 'B'; + cbw.dCBWSignature[3] = 'C'; + cbw.dCBWTag = 0x01234567; + cbw.dCBWDataTransferLength = 0x60; + cbw.bmCBWFlags = 0x80; + cbw.bCBWLUN = 0; + cbw.bCBWCBLength = 6; + cbw.CBWCB[0] = 0x12; // Inquiry + cbw.CBWCB[4] = 0x60; // Inquiry data size + + CALL_CHECK(libusb_bulk_transfer(handle, 0x01, (unsigned char*)&cbw, 22, &size, 100)); + printf("sent %d bytes\n", size); + CALL_CHECK(libusb_bulk_transfer(handle, 0x81, (unsigned char*)&buffer, 0x60, &size, 100)); + printf("received %d bytes\n", size); + printf("VID:PID:REV:SPE %s:%s:%s:%s\n", &buffer[8], &buffer[16], &buffer[32], &buffer[38]); return 0; } @@ -172,6 +198,7 @@ int test_device(uint16_t vid, uint16_t pid) const struct libusb_endpoint_descriptor *endpoint; int i, j, k, r; int iface, nb_ifaces; + int test_scsi = 0; printf("Opening device...\n"); handle = libusb_open_device_with_vid_pid(NULL, vid, pid); @@ -206,6 +233,12 @@ int test_device(uint16_t vid, uint16_t pid) conf_desc->interface[i].altsetting[j].bInterfaceClass, conf_desc->interface[i].altsetting[j].bInterfaceSubClass, conf_desc->interface[i].altsetting[j].bInterfaceProtocol); + if ( (conf_desc->interface[i].altsetting[j].bInterfaceClass == LIBUSB_CLASS_MASS_STORAGE) + && ( (conf_desc->interface[i].altsetting[j].bInterfaceSubClass == 0x01) + || (conf_desc->interface[i].altsetting[j].bInterfaceSubClass == 0x06) ) ) { + // Mass storage devices that can use basic SCSI commands + test_scsi = -1; + } for (k=0; k<conf_desc->interface[i].altsetting[j].bNumEndpoints; k++) { endpoint = &conf_desc->interface[i].altsetting[j].endpoint[k]; printf(" endpoint[%d].address: %02X\n", k, endpoint->bEndpointAddress); @@ -245,7 +278,7 @@ int test_device(uint16_t vid, uint16_t pid) printf("Got string: \"%s\"\n", string); } - if (test_mode == USE_KEY) { + if (test_scsi) { CALL_CHECK(test_mass_storage(handle)); } diff --git a/libusb/os/windows_compat.c b/libusb/os/windows_compat.c index f0ec41b..6259cbb 100644 --- a/libusb/os/windows_compat.c +++ b/libusb/os/windows_compat.c @@ -35,7 +35,7 @@ * pollable fds * - leave the core functions call the poll routine and flag POLLIN/POLLOUT * - * For pipe pollavle synchronous I/O (read end polling only), you would: + * For pipe pollable synchronous I/O (read end polling only), you would: * - create an anonymous pipe with pipe_for_poll to obtain 2 fds (r & w) * - use write_for_poll / read_for_poll to write to either end of the pipe * - use poll to check for data to read @@ -60,6 +60,11 @@ * use the OVERLAPPED directly (which is what we do in the USB async I/O * functions), the marker is not used at all. */ + +/* + * TODO: Once MinGW supports it (or for other compilation platforms) use + * CancelIoEx instead of CancelIo for Vista and later platforms + */ #include <errno.h> #include <fcntl.h> #include <stdio.h> @@ -68,6 +73,7 @@ #include "windows_compat.h" +// Uncomment to debug the polling layer //#define DEBUG_WINDOWS_COMPAT #ifdef DEBUG_WINDOWS_COMPAT #define printb(...) printf(__VA_ARGS__) @@ -75,11 +81,6 @@ #define printb(...) #endif -// Required for MinGW as the default WINNT_VER is too low -#ifndef FILE_FLAG_FIRST_PIPE_INSTANCE -#define FILE_FLAG_FIRST_PIPE_INSTANCE 524288 -#endif - #define CHECK_INIT_POLLING do {if(!is_polling_set) init_polling();} while(0)
// public fd data @@ -87,8 +88,8 @@ const struct winfd INVALID_WINFD = {-1, NULL, NULL, RW_NONE}; struct winfd poll_fd[MAX_FDS]; // internal fd data struct { - pthread_mutex_t mutex; // thread mutex lock for fds - BYTE marker; // 1st byte of a read_for_poll operation gets stored here + pthread_mutex_t mutex; // thread mutex lock for fds + BYTE marker; // 1st byte of a read_for_poll operation gets stored here } _poll_fd[MAX_FDS]; @@ -262,7 +263,7 @@ int pipe_for_poll(int filedes[2]) filedes[1] = _open_osfhandle((intptr_t)handle[1], _O_WRONLY); printb("filedes[1] = %d\n", filedes[1]); - // Now let's set ourselves some OVERLAPPED + // Create an OVERLAPPED for each end overlapped[0].hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if(!overlapped[0].hEvent) { goto out3; @@ -373,9 +374,6 @@ struct winfd create_fd_for_poll(HANDLE handle, int access_mode) void _free_index(int index) { // Cancel any async IO (Don't care about the validity of our handles for this) - // TODO: Once MinGW supports it (or for other compilation platforms) use - // CancelIoEx for Vista and later -// CancelIoEx(poll_fd[index].handle, poll_fd[index].overlapped); CancelIo(poll_fd[index].handle); // close fake handle for devices if ( (poll_fd[index].handle != INVALID_HANDLE_VALUE) && (poll_fd[index].handle != 0) @@ -473,7 +471,7 @@ struct winfd overlapped_to_winfd(OVERLAPPED* overlapped) /* * POSIX poll equivalent, using Windows OVERLAPPED - * Currently, this function can only accept one of POLLIN or POLLOUT per fd + * Currently, this function only accepts one of POLLIN or POLLOUT per fd * (but you can create multiple fds from the same handle for read and write) */ int poll(struct pollfd *fds, unsigned int nfds, int timeout) @@ -486,7 +484,6 @@ int poll(struct pollfd *fds, unsigned int nfds, int timeout) CHECK_INIT_POLLING; - // TODO: malloc'ing on each poll is not super-efficient if ((handles_to_wait_on == NULL) || (handle_to_index == NULL)) { errno = ENOMEM; return -1; diff --git a/libusb/os/windows_usb.c b/libusb/os/windows_usb.c index e372396..9e00d3a 100644 --- a/libusb/os/windows_usb.c +++ b/libusb/os/windows_usb.c @@ -17,23 +17,6 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -/* - * Design considerations: - * - * No matter where it happens, a failed malloc is a critical error and will - * abort whichever section of code is running. - * - * Both our buses and device addresses are zero indexed rather than 1 indexed - * for convenience reasons (post HCD devaddr start at 1 on window, and we need - * to set a devaddr for the non enumerated HCD hub) - * - * While we try to work around OS errors by skipping the device/op whenever - * possible (and produce a warning), any libusb calls returning an error is - * treated as a potential critical bug and cause for an immediate abort of - * the function that called it. - */ - #include <config.h> #include <ctype.h> #include <dirent.h> @@ -77,6 +60,7 @@ #define LOOP_CONTINUE(...) { usbi_warn(ctx, __VA_ARGS__); continue; } #define LOOP_BREAK(err) { r=err; continue; } +// Helper prototypes static int windows_get_active_config_descriptor(struct libusb_device *dev, unsigned char *buffer, size_t len, int *host_endian); static int windows_clock_gettime(int clk_id, struct timespec *tp); // WinUSB API prototypes @@ -95,16 +79,15 @@ static int winusb_abort_transfers(struct usbi_transfer *itransfer); static int winusb_abort_control(struct usbi_transfer *itransfer); static int winusb_reset_device(struct libusb_device_handle *dev_handle); -// HCD private chained list +// Global variables struct windows_hcd_priv* hcd_root = NULL; -// timers uint64_t hires_frequency, hires_ticks_to_ps; -// 1970.01.01 00:00:000 in MS Filetime, as computed and confirmed with google -const uint64_t epoch_time = 116444736000000000; +const uint64_t epoch_time = 116444736000000000; // 1970.01.01 00:00:000 in MS Filetime DWORD_PTR old_affinity_mask; +enum windows_version windows_version = WINDOWS_UNSUPPORTED; +// WinUSB globals bool api_winusb_available = false; #define CHECK_WINUSB_AVAILABLE do { if (!api_winusb_available) return LIBUSB_ERROR_ACCESS; } while (0) -enum windows_version windows_version = WINDOWS_UNSUPPORTED; /* * Converts a WCHAR string to UTF8 (allocate returned string) @@ -206,7 +189,7 @@ static char* sanitize_path(const char* path) } /* - * This function, which should be called repeatedly, enumerates the interfaces for a specific GUID + * enumerate interfaces for a specific GUID * * Parameters: * dev_info: a pointer to a dev_info list @@ -214,8 +197,8 @@ static char* sanitize_path(const char* path) * index: zero based index of the interface in the device info list * * Note: it is the responsibility of the caller to free the DEVICE_INTERFACE_DETAIL_DATA - * structure returned and use the same guid, with an incremented index starting at zero, - * until all interfaces have been returned + * structure returned and call this function repeatedly using the same guid (with an + * incremented index starting at zero) until all interfaces have been returned. */ SP_DEVICE_INTERFACE_DETAIL_DATA *get_interface_details(struct libusb_context *ctx, HDEVINFO* dev_info, GUID guid, unsigned index) { @@ -298,45 +281,6 @@ static void windows_assign_endpoints(struct libusb_device *dev, int iface, int a } }
-/*
- * Lookup interface by endpoint address. -1 if not found
- */
-static int interface_by_endpoint(struct windows_device_priv *priv, - struct windows_device_handle_priv *handle_priv, uint8_t endpoint_address) -{ - int i, j;
- for (i=0; i<USB_MAXINTERFACES; i++) {
- if (handle_priv->interface_handle[i].winusb == INVALID_HANDLE_VALUE)
- continue;
- if (handle_priv->interface_handle[i].winusb == 0)
- continue;
- if (priv->interface[i].endpoint == NULL)
- continue;
- for (j=0; j<priv->interface[i].nb_endpoints; j++) {
- if (priv->interface[i].endpoint[j] == endpoint_address) {
- return i;
- }
- }
- }
- return -1;
-}
-
-/*
- * Return the first valid WinUSB handle, for control transfers
- */
-static int get_any_active_interface(struct windows_device_handle_priv *handle_priv)
-{
- int i;
- - for (i=0; i<USB_MAXINTERFACES; i++) { - if ( (handle_priv->interface_handle[i].winusb != 0) - && (handle_priv->interface_handle[i].winusb != INVALID_HANDLE_VALUE)) { - return i; - } - } - return -1;
-}
-
/* * init: libusb backend init function * @@ -365,22 +309,21 @@ static int windows_init(struct libusb_context *ctx) os_version.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
windows_version = WINDOWS_UNSUPPORTED;
if ((GetVersionEx(&os_version) != 0) && (os_version.dwPlatformId == VER_PLATFORM_WIN32_NT)) { - if ((os_version.dwMajorVersion == 5) && (os_version.dwMinorVersion == 0)) {
- windows_version = WINDOWS_2000;
- } else if ((os_version.dwMajorVersion == 5) && (os_version.dwMinorVersion == 1)) {
+ if ((os_version.dwMajorVersion == 5) && (os_version.dwMinorVersion == 1)) {
windows_version = WINDOWS_XP;
} else if (os_version.dwMajorVersion >= 6) {
windows_version = WINDOWS_VISTA_AND_LATER;
}
} - if (windows_version < WINDOWS_XP) { - usbi_warn(ctx, "This version of Windows is NOT supported"); + if (windows_version == WINDOWS_UNSUPPORTED) { + usbi_err(ctx, "This version of Windows is NOT supported"); + return LIBUSB_ERROR_NOT_SUPPORTED; } // Initialize pollable file descriptors init_polling(); - // Initialize the API + // Initialize the low level APIs r = winusb_api_init(ctx); if (r != LIBUSB_SUCCESS) { return r; @@ -455,7 +398,6 @@ static int initialize_device(struct libusb_device *dev, libusb_bus_t busnum, { struct windows_device_priv *priv = __device_priv(dev); - // Set default values windows_device_priv_init(priv); dev->bus_number = busnum; @@ -499,7 +441,6 @@ static int force_hcd_device_descriptor(struct libusb_device *dev, HANDLE handle) dev->num_configurations = priv->dev_descriptor.bNumConfigurations = 1; priv->dev_descriptor.idVendor = 0x1d6b; // Linux Foundation root hub - // The EX query was implemented in Vista if (windows_version >= WINDOWS_VISTA_AND_LATER) { size = sizeof(USB_HUB_CAPABILITIES_EX); if (DeviceIoControl(handle, IOCTL_USB_GET_HUB_CAPABILITIES_EX, &hub_caps_ex, @@ -511,7 +452,6 @@ static int force_hcd_device_descriptor(struct libusb_device *dev, HANDLE handle) priv->dev_descriptor.idProduct = hub_caps_ex.CapabilityFlags.HubIsHighSpeedCapable?2:1; } } else { - // Standard query size = sizeof(USB_HUB_CAPABILITIES); if (!DeviceIoControl(handle, IOCTL_USB_GET_HUB_CAPABILITIES, &hub_caps, size, &hub_caps, size, &size, NULL)) { @@ -536,15 +476,13 @@ static int cache_config_descriptors(struct libusb_device *dev, HANDLE hub_handle int r; uint8_t i; - USB_CONFIGURATION_DESCRIPTOR_SHORT cd_buf_short; // dummy request - PUSB_DESCRIPTOR_REQUEST cd_buf_actual = NULL; // actual request + USB_CONFIGURATION_DESCRIPTOR_SHORT cd_buf_short; // dummy request + PUSB_DESCRIPTOR_REQUEST cd_buf_actual = NULL; // actual request PUSB_CONFIGURATION_DESCRIPTOR cd_data = NULL; - // Report an error if there are no configs available if (dev->num_configurations == 0) return LIBUSB_ERROR_INVALID_PARAM; - // Allocate the list of pointers to the descriptors priv->config_descriptor = malloc(dev->num_configurations * sizeof(PUSB_CONFIGURATION_DESCRIPTOR)); if (priv->config_descriptor == NULL) return LIBUSB_ERROR_NO_MEM; @@ -656,7 +594,7 @@ static int usb_enumerate_hub(struct libusb_context *ctx, struct discovered_devs // obviously, root (HCD) hubs have no parent is_hcd = (parent_dev == NULL); if (is_hcd) - { // HCD root hub + { if (nb_ports != 1) { usbi_warn(ctx, "program assertion failed - invalid number of ports for HCD."); return LIBUSB_ERROR_INVALID_PARAM; @@ -667,7 +605,7 @@ static int usb_enumerate_hub(struct libusb_context *ctx, struct discovered_devs getname_ioctl = IOCTL_USB_GET_ROOT_HUB_NAME; } else - { // Node + { parent_priv = __device_priv(parent_dev); size_initial = sizeof(USB_NODE_CONNECTION_NAME); size_fixed = sizeof(USB_NODE_CONNECTION_NAME_FIXED); @@ -728,8 +666,8 @@ static int usb_enumerate_hub(struct libusb_context *ctx, struct discovered_devs LOOP_CONTINUE("program assertion failed - hub path is too long"); } - // ConnectionIndex needs to be written again for the actual query if (!is_hcd) { + // previous call trashes some of the data s_hubname.u.node.ConnectionIndex = i; } if (!DeviceIoControl(hub_handle, getname_ioctl, &s_hubname, size, @@ -788,7 +726,6 @@ static int usb_enumerate_hub(struct libusb_context *ctx, struct discovered_devs path_str = NULL; // protect our path from being freed // Setup the cached descriptors. Note that only non HCDs can fetch descriptors - // For HCDs, we just populate it manually if (!is_hcd) { // The device descriptor has been read with conn_info memcpy(&priv->dev_descriptor, &(conn_info.DeviceDescriptor), sizeof(USB_DEVICE_DESCRIPTOR)); @@ -804,7 +741,6 @@ static int usb_enumerate_hub(struct libusb_context *ctx, struct discovered_devs LOOP_CHECK(usbi_sanitize_device(dev)); } - // Append the device to the list of discovered devices discdevs = discovered_devs_append(*_discdevs, dev); if (!discdevs) { LOOP_BREAK(LIBUSB_ERROR_NO_MEM); @@ -830,7 +766,6 @@ static int usb_enumerate_hub(struct libusb_context *ctx, struct discovered_devs usbi_dbg("%d ports Hub: %s", hub_node.u.HubInformation.HubDescriptor.bNumberOfPorts, priv->path); - // More hubs (NB: we don't really care about the value returned) usb_enumerate_hub(ctx, _discdevs, handle, busnum, dev, hub_node.u.HubInformation.HubDescriptor.bNumberOfPorts); } @@ -882,7 +817,6 @@ static int set_composite_device(struct libusb_context *ctx, DEVINST devinst, str continue; } - // We'll need a WCHAR string to convert to GUID if (RegQueryValueExW(key, L"DeviceInterfaceGUIDs", NULL, &type, (BYTE*)guid_string_w, &size) != ERROR_SUCCESS) { RegCloseKey(key); continue; @@ -921,8 +855,9 @@ static int set_composite_device(struct libusb_context *ctx, DEVINST devinst, str if (dev_interface_details == NULL) break; - // Check the driver to weed out non WinUSB interfaces (which can happen + // For now, we weed out all non WinUSB interfaces (which can happen // with a mix of WinUSB and proprietary drivers on composite devices) + // If other APIs are supported, other drivers need to be added dev_info_data.cbSize = sizeof(dev_info_data); if (!SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data)) { LOOP_CONTINUE("could not retrieve info data: %s", windows_error_str(0)); @@ -946,7 +881,7 @@ static int set_composite_device(struct libusb_context *ctx, DEVINST devinst, str // Finally, match the interface paths with the interfaces. We do that // by looking at the children of the composite device // NB: if the interfaces are not found in their expected position, - // claim_interface will produce a warning + // claim_interface will issue a warning found = false; for (interface_number = 0; interface_number<USB_MAXINTERFACES; interface_number++) { @@ -1019,10 +954,7 @@ static int set_device_paths(struct libusb_context *ctx, struct discovered_devs * unsigned i, j, port_nr, hub_nr; bool found; - /* - * List connected devices that are not a hub - * TODO: MI_## automated driver installation: - */ + // TODO: MI_## automated driver installation: guid = GUID_DEVINTERFACE_USB_DEVICE; for (i = 0; ; i++) { @@ -1106,9 +1038,8 @@ static int set_device_paths(struct libusb_context *ctx, struct discovered_devs * for (j=0; j<discdevs->len; j++) { priv = __device_priv(discdevs->devices[j]); - // ignore HCDs if (priv->parent_dev == NULL) { - continue; + continue; // ignore HCDs } parent_priv = __device_priv(priv->parent_dev); @@ -1140,16 +1071,17 @@ static int set_device_paths(struct libusb_context *ctx, struct discovered_devs * priv->api = API_WINUSB; // For non composite, the first interface is the same as the device priv->interface[0].path = safe_strdup(priv->path); // needs strdup - // Composite (multi-interface) devices are identified by their use of - // the USB Common Class Generic Parent driver } else if (safe_strcmp(reg_key, "usbccgp") == 0) { - // Sets the path of all available interfaces of the composite device + // Composite (multi-interface) devices are identified by their use of + // the USB Common Class Generic Parent driver if (set_composite_device(ctx, dev_info_data.DevInst, priv) == LIBUSB_SUCCESS) { priv->api = API_WINUSB; } else { priv->api = API_NONE; } - } + } else { + // All other USB access drivers (HID, Mass Storage) are ignored for now + } break; } } @@ -1171,7 +1103,7 @@ static int windows_get_device_list(struct libusb_context *ctx, struct discovered int r = LIBUSB_SUCCESS; libusb_bus_t bus; - // We use the index of the HCD in the chained list as bus # + // Use the index of the HCD in the chained list as bus # for (hcd = hcd_root, bus = 0; ; hcd = hcd->next, bus++) { safe_closehandle(handle); @@ -1179,7 +1111,6 @@ static int windows_get_device_list(struct libusb_context *ctx, struct discovered if ( (hcd == NULL) || (r != LIBUSB_SUCCESS) ) break; - // Shouldn't be needed, but let's be safe if (bus == LIBUSB_BUS_MAX) { LOOP_CONTINUE("program assertion failed - got more than %d buses, skipping the rest.", LIBUSB_BUS_MAX); } @@ -1193,7 +1124,7 @@ static int windows_get_device_list(struct libusb_context *ctx, struct discovered LOOP_CHECK(usb_enumerate_hub(ctx, _discdevs, handle, bus, NULL, 1)); } - // Non hub device paths are set using a separate method + // Set the interface path for non-hubs r = set_device_paths(ctx, *_discdevs); return r; @@ -1226,16 +1157,12 @@ static int windows_get_device_descriptor(struct libusb_device *dev, unsigned cha { struct windows_device_priv *priv = __device_priv(dev); - // return cached copy - memmove(buffer, &(priv->dev_descriptor), DEVICE_DESC_LENGTH); + memcpy(buffer, &(priv->dev_descriptor), DEVICE_DESC_LENGTH); *host_endian = 0; return LIBUSB_SUCCESS; } -/* - * return the cached copy of the relevant config descriptor - */ static int windows_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian) { struct windows_device_priv *priv = __device_priv(dev); @@ -1264,11 +1191,10 @@ static int windows_get_active_config_descriptor(struct libusb_device *dev, unsig { struct windows_device_priv *priv = __device_priv(dev); - // Has active config been set yet if (priv->active_config == 0) return LIBUSB_ERROR_NOT_FOUND; - // config indexes for get_config_descriptors start at zero + // config index is zero based return windows_get_config_descriptor(dev, priv->active_config-1, buffer, len, host_endian); } @@ -1295,9 +1221,6 @@ static void windows_close(struct libusb_device_handle *dev_handle) } } -/* - * Get the bConfigurationValue for the active configuration for a device. - */ static int windows_get_configuration(struct libusb_device_handle *dev_handle, int *config) { struct windows_device_priv *priv = __device_priv(dev_handle->dev); @@ -1307,9 +1230,9 @@ static int windows_get_configuration(struct libusb_device_handle *dev_handle, in } /*
- * from http://msdn.microsoft.com/en-us/library/ms793522.aspx: The port driver
+ * from http://msdn.microsoft.com/en-us/library/ms793522.aspx: "The port driver
* does not currently expose a service that allows higher-level drivers to set
- * the configuration.
+ * the configuration."
* The current version of this function still attempts to change conf to see
* what happens...
*/
@@ -1328,7 +1251,7 @@ static int windows_set_configuration(struct libusb_device_handle *dev_handle, in if (r == LIBUSB_SUCCESS) { // TODO: If the above ever works, some code will be needed here // to invalidate the endpoints & interfaces - usbi_dbg("against all odds, it worked! - needs some code"); + usbi_dbg("against all odds, it worked! - now add some code"); } return r; @@ -1538,31 +1461,7 @@ static void windows_clear_transfer_priv(struct usbi_transfer *itransfer) free_fd_for_poll(transfer_priv->pollable_fd.fd); } -static void windows_control_callback (struct usbi_transfer *itransfer, uint32_t io_result, uint32_t io_size) -{ - int status; - - usbi_dbg("handling control completion with status %d", io_result); - - switch(io_result) { - case NO_ERROR: - status = LIBUSB_TRANSFER_COMPLETED; - itransfer->transferred += io_size; - break; - case ERROR_GEN_FAILURE: // is the error we get for unsupported on Windows - usbi_dbg("unsupported control request"); - status = LIBUSB_TRANSFER_STALL; - break; - default: - usbi_err(ITRANSFER_CTX(itransfer), "control error: %s", windows_error_str(0)); - status = LIBUSB_TRANSFER_ERROR; - break; - } - - usbi_handle_transfer_completion(itransfer, status); -} - -static void windows_bulk_callback (struct usbi_transfer *itransfer, uint32_t io_result, uint32_t io_size) +static void windows_transfer_callback (struct usbi_transfer *itransfer, uint32_t io_result, uint32_t io_size) { int status; @@ -1592,15 +1491,10 @@ static void windows_handle_callback (struct usbi_transfer *itransfer, uint32_t i switch (transfer->type) { case LIBUSB_TRANSFER_TYPE_CONTROL: - windows_control_callback (itransfer, io_result, io_size); - break; case LIBUSB_TRANSFER_TYPE_BULK: case LIBUSB_TRANSFER_TYPE_INTERRUPT: - windows_bulk_callback (itransfer, io_result, io_size); - break; case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: - // TODO: ain't gonna happen with WinUSB only -// windows_isoc_callback (itransfer, io_result); + windows_transfer_callback (itransfer, io_result, io_size); break; default: usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type); @@ -1626,8 +1520,8 @@ static int windows_handle_events(struct libusb_context *ctx, struct pollfd *fds, num_ready--; - // Using transfer_priv to store our polling data - // is the most logical choice for now + // Because a Windows OVERLAPPED is used for poll emulation, + // a pollable fd is created and stored with each transfer list_for_each_entry(transfer, &ctx->flying_transfers, list) { transfer_priv = usbi_transfer_get_os_priv(transfer); if (transfer_priv->pollable_fd.fd == fds[i].fd) { @@ -1736,7 +1630,6 @@ const struct usbi_os_backend windows_backend = { /* * WinUSB API functions */ - static int winusb_api_init(struct libusb_context *ctx) { DLL_LOAD(winusb.dll, WinUsb_Initialize, TRUE); @@ -1778,7 +1671,7 @@ static int winusb_open(struct libusb_device_handle *dev_handle) CHECK_WINUSB_AVAILABLE; - // Each interface requires a sperate handle for WinUSB + // WinUSB requires a seperate handle for each interface for (i = 0; i < USB_MAXINTERFACES; i++) { if (priv->interface[i].path != NULL) { file_handle = CreateFileA(priv->interface[i].path, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, @@ -1891,6 +1784,7 @@ static int winusb_claim_interface(struct libusb_device_handle *dev_handle, int i // With handle and enpoints set (in parent), we can setup the default // pipe properties (copied from libusb-win32-v1) + // see http://download.microsoft.com/download/D/1/D/D1DD7745-426B-4CC3-A269-ABBBE427C0EF/DVC-T705_DDC08.pptx for (i=0; i<priv->interface[iface].nb_endpoints; i++) { endpoint_address = priv->interface[iface].endpoint[i]; policy = false; @@ -1933,6 +1827,45 @@ static int winusb_release_interface(struct libusb_device_handle *dev_handle, int return LIBUSB_SUCCESS; } +/*
+ * Return the first valid WinUSB handle, for control transfers
+ */
+static int winusb_get_valid_interface(struct windows_device_handle_priv *handle_priv)
+{
+ int i;
+ + for (i=0; i<USB_MAXINTERFACES; i++) { + if ( (handle_priv->interface_handle[i].winusb != 0) + && (handle_priv->interface_handle[i].winusb != INVALID_HANDLE_VALUE)) { + return i; + } + } + return -1;
+} + +/*
+ * Lookup interface by endpoint address. -1 if not found
+ */
+static int winusb_interface_by_endpoint(struct windows_device_priv *priv, + struct windows_device_handle_priv *handle_priv, uint8_t endpoint_address) +{ + int i, j;
+ for (i=0; i<USB_MAXINTERFACES; i++) {
+ if (handle_priv->interface_handle[i].winusb == INVALID_HANDLE_VALUE)
+ continue;
+ if (handle_priv->interface_handle[i].winusb == 0)
+ continue;
+ if (priv->interface[i].endpoint == NULL)
+ continue;
+ for (j=0; j<priv->interface[i].nb_endpoints; j++) {
+ if (priv->interface[i].endpoint[j] == endpoint_address) {
+ return i;
+ }
+ }
+ }
+ return -1;
+} + static int winusb_submit_control_transfer(struct usbi_transfer *itransfer) { struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); @@ -1953,7 +1886,7 @@ static int winusb_submit_control_transfer(struct usbi_transfer *itransfer) if (size > MAX_CTRL_BUFFER_LENGTH) return LIBUSB_ERROR_INVALID_PARAM; - current_interface = get_any_active_interface(handle_priv); + current_interface = winusb_get_valid_interface(handle_priv); if (current_interface < 0) { usbi_err(ctx, "no active interface"); return LIBUSB_ERROR_NOT_FOUND; @@ -1974,12 +1907,13 @@ static int winusb_submit_control_transfer(struct usbi_transfer *itransfer) return LIBUSB_ERROR_IO;
}
} else {
+ // TODO: find out if this ever happens through user test reports
usbi_err(ctx, "chill out man; this is like way too fast for async I/O...");
free_fd_for_poll(wfd.fd);
return LIBUSB_ERROR_IO; }
- // Again, use priv_transfer to store data needed for async polling
+ // Use priv_transfer to store data needed for async polling
transfer_priv->pollable_fd = wfd;
return LIBUSB_SUCCESS;
@@ -2023,7 +1957,7 @@ static int winusb_submit_bulk_transfer(struct usbi_transfer *itransfer) transfer_priv->pollable_fd = INVALID_WINFD; - current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint);
+ current_interface = winusb_interface_by_endpoint(priv, handle_priv, transfer->endpoint);
if (current_interface < 0) {
usbi_err(ctx, "unable to match endpoint to an open interface - cancelling transfer");
return LIBUSB_ERROR_NOT_FOUND;
@@ -2053,6 +1987,7 @@ static int winusb_submit_bulk_transfer(struct usbi_transfer *itransfer) return LIBUSB_ERROR_IO;
}
} else {
+ // TODO: find out if this ever happens through user test reports
usbi_err(ctx, "chill out man; this is like way too fast for async I/O...");
free_fd_for_poll(wfd.fd);
return LIBUSB_ERROR_IO; @@ -2078,7 +2013,7 @@ static int winusb_clear_halt(struct libusb_device_handle *dev_handle, unsigned c CHECK_WINUSB_AVAILABLE;
- current_interface = interface_by_endpoint(priv, handle_priv, endpoint);
+ current_interface = winusb_interface_by_endpoint(priv, handle_priv, endpoint);
if (current_interface < 0) {
usbi_err(ctx, "unable to match endpoint to an open interface - cannot clear");
return LIBUSB_ERROR_NOT_FOUND;
@@ -2128,7 +2063,7 @@ static int winusb_abort_transfers(struct usbi_transfer *itransfer) // Cancel the I/O free_fd_for_poll(transfer_priv->pollable_fd.fd); - current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint);
+ current_interface = winusb_interface_by_endpoint(priv, handle_priv, transfer->endpoint);
if (current_interface < 0) {
usbi_err(ctx, "unable to match endpoint to an open interface - cancelling abort");
return LIBUSB_ERROR_NOT_FOUND;
@@ -2168,14 +2103,25 @@ static int winusb_reset_device(struct libusb_device_handle *dev_handle) // Reset any available pipe (except control)
for (i=0; i<USB_MAXINTERFACES; i++) { winusb_handle = handle_priv->interface_handle[i].winusb; - // Cancel any pending I/O do { wfd = handle_to_winfd(winusb_handle); - free_fd_for_poll(wfd.fd); + free_fd_for_poll(wfd.fd); // Cancel any pending I/O } while (wfd.fd > 0); if ( (winusb_handle != 0) && (winusb_handle != INVALID_HANDLE_VALUE)) { for (j=0; j<priv->interface[i].nb_endpoints; j++) { + usbi_dbg("resetting ep %02X", priv->interface[i].endpoint[j]); + // TODO: looks like whatever you try here, you can't get an actual reset of the ep + if (!WinUsb_AbortPipe(winusb_handle, priv->interface[i].endpoint[j])) {
+ usbi_err(ctx, "WinUsb_AbortPipe (pipe address %02X) failed: %s", + priv->interface[i].endpoint[j], windows_error_str(0)); + } + // FlushPipe seems to fail on OUT pipes + if ( (priv->interface[i].endpoint[j] & LIBUSB_ENDPOINT_IN)
+ && (!WinUsb_FlushPipe(winusb_handle, priv->interface[i].endpoint[j])) ) {
+ usbi_err(ctx, "WinUsb_FlushPipe (pipe address %02X) failed: %s", + priv->interface[i].endpoint[j], windows_error_str(0)); + } if (!WinUsb_ResetPipe(winusb_handle, priv->interface[i].endpoint[j])) {
usbi_err(ctx, "WinUsb_ResetPipe (pipe address %02X) failed: %s", priv->interface[i].endpoint[j], windows_error_str(0)); diff --git a/libusb/os/windows_usb.h b/libusb/os/windows_usb.h index 9534620..3ecdd68 100644 --- a/libusb/os/windows_usb.h +++ b/libusb/os/windows_usb.h @@ -31,7 +31,6 @@ #define false FALSE #endif -// Make sure you keep these in check with what libusb uses for its device declaration #if !defined(libusb_bus_t) #define libusb_bus_t uint8_t #define LIBUSB_BUS_MAX UINT8_MAX @@ -41,7 +40,6 @@ #define LIBUSB_DEVADDR_MAX UINT8_MAX #endif -// Better safe than sorry... #define safe_free(p) do {if (p != NULL) {free(p); p = NULL;}} while(0) #define safe_closehandle(h) do {if (h != INVALID_HANDLE_VALUE) {CloseHandle(h); h = INVALID_HANDLE_VALUE;}} while(0) #define safe_strncpy(dst, dst_max, src, count) strncpy(dst, src, min(count, dst_max - 1)) @@ -71,7 +69,7 @@ void inline upperize(char* str) { #define wchar_to_utf8_ms(wstr, str, strlen) WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, strlen, NULL, NULL) #define ERRNO GetLastError() -// API (driver access) types +// Supported APIs enum api_type { API_NONE, API_WINUSB, @@ -91,7 +89,6 @@ enum api_type { enum windows_version { WINDOWS_UNSUPPORTED, - WINDOWS_2000, WINDOWS_XP, WINDOWS_VISTA_AND_LATER, }; @@ -223,34 +220,6 @@ typedef struct _USB_CONFIGURATION_DESCRIPTOR_SHORT { } USB_CONFIGURATION_DESCRIPTOR_SHORT; #pragma pack() - -/* - * Some of the EX stuff is not yet in MinGW => define it - */ -#ifndef USB_GET_NODE_CONNECTION_INFORMATION_EX -#define USB_GET_NODE_CONNECTION_INFORMATION_EX 274 -#endif - -#ifndef IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX -#define IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX \ - CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_INFORMATION_EX, \ - METHOD_BUFFERED, FILE_ANY_ACCESS) -#endif - -#ifndef USB_NODE_CONNECTION_INFORMATION_EX -typedef struct _USB_NODE_CONNECTION_INFORMATION_EX { - ULONG ConnectionIndex; - USB_DEVICE_DESCRIPTOR DeviceDescriptor; - UCHAR CurrentConfigurationValue; - UCHAR Speed; - BOOLEAN DeviceIsHub; - USHORT DeviceAddress; - ULONG NumberOfOpenPipes; - USB_CONNECTION_STATUS ConnectionStatus; - USB_PIPE_INFO PipeList[0]; -} USB_NODE_CONNECTION_INFORMATION_EX, *PUSB_NODE_CONNECTION_INFORMATION_EX; -#endif - #ifndef USB_HUB_CAP_FLAGS typedef union _USB_HUB_CAP_FLAGS { ULONG ul; |