summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPete Batard <pbatard@gmail.com>2011-02-21 15:35:50 +0000
committerPete Batard <pbatard@gmail.com>2011-02-21 15:35:50 +0000
commitc537f6f9d922e5ed75562618d3b6b069feb6b4a2 (patch)
tree44882e2036aaf9cad5663bb4034942d73a6aefa5
parentb0a72dd7a7f57113772103673c8fca390021c52c (diff)
downloadlibusb-c537f6f9d922e5ed75562618d3b6b069feb6b4a2.tar.gz
prevent set_configuration request from being sent using WinUSB
* multiple WinUSB set configuration requests can stall a device and WinUSB does not support setting of alt configuration in the first place * issue reported and investigated by Xiaofan Chen
-rw-r--r--libusb/os/windows_usb.c25
1 files changed, 19 insertions, 6 deletions
diff --git a/libusb/os/windows_usb.c b/libusb/os/windows_usb.c
index 380adb2..2435f76 100644
--- a/libusb/os/windows_usb.c
+++ b/libusb/os/windows_usb.c
@@ -2724,6 +2724,7 @@ static int winusb_submit_control_transfer(struct usbi_transfer *itransfer)
{
struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
+ struct windows_device_priv *priv = __device_priv(transfer->dev_handle->dev);
struct windows_transfer_priv *transfer_priv = (struct windows_transfer_priv*)usbi_transfer_get_os_priv(itransfer);
struct windows_device_handle_priv *handle_priv = __device_handle_priv(
transfer->dev_handle);
@@ -2762,15 +2763,27 @@ static int winusb_submit_control_transfer(struct usbi_transfer *itransfer)
return LIBUSB_ERROR_NO_MEM;
}
- if (!WinUsb_ControlTransfer(wfd.handle, *setup, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, size, NULL, wfd.overlapped)) {
- if(GetLastError() != ERROR_IO_PENDING) {
- usbi_err(ctx, "WinUsb_ControlTransfer failed: %s", windows_error_str(0));
+ // Sending of set configuration control requests from WinUSB creates issues
+ if ( (LIBUSB_REQ_TYPE(setup->request_type) == LIBUSB_REQUEST_TYPE_STANDARD)
+ && (setup->request == LIBUSB_REQUEST_SET_CONFIGURATION) ) {
+ if (setup->value != priv->active_config) {
+ usbi_warn(ctx, "cannot set configuration other than the default one");
usbi_free_fd(wfd.fd);
- return LIBUSB_ERROR_IO;
+ return LIBUSB_ERROR_INVALID_PARAM;
}
- } else {
wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY;
- wfd.overlapped->InternalHigh = (DWORD)size;
+ wfd.overlapped->InternalHigh = 0;
+ } else {
+ if (!WinUsb_ControlTransfer(wfd.handle, *setup, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, size, NULL, wfd.overlapped)) {
+ if(GetLastError() != ERROR_IO_PENDING) {
+ usbi_err(ctx, "WinUsb_ControlTransfer failed: %s", windows_error_str(0));
+ usbi_free_fd(wfd.fd);
+ return LIBUSB_ERROR_IO;
+ }
+ } else {
+ wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY;
+ wfd.overlapped->InternalHigh = (DWORD)size;
+ }
}
// Use priv_transfer to store data needed for async polling