diff options
Diffstat (limited to 'libusb/os/windows_winusb.c')
-rw-r--r-- | libusb/os/windows_winusb.c | 293 |
1 files changed, 136 insertions, 157 deletions
diff --git a/libusb/os/windows_winusb.c b/libusb/os/windows_winusb.c index f4e6931..8ff815b 100644 --- a/libusb/os/windows_winusb.c +++ b/libusb/os/windows_winusb.c @@ -789,9 +789,6 @@ static int windows_init(struct libusb_context *ctx) // We need a lock for proper auto-release usbi_mutex_init(&autoclaim_lock); - // Initialize pollable file descriptors - init_polling(); - // Load DLL imports if (init_dlls() != LIBUSB_SUCCESS) { usbi_err(ctx, "could not resolve DLL functions"); @@ -819,7 +816,6 @@ init_exit: // Holds semaphore here. usb_api_backend[i].exit(); } exit_dlls(); - exit_polling(); windows_common_exit(); usbi_mutex_destroy(&autoclaim_lock); } @@ -1741,7 +1737,6 @@ static void windows_exit(struct libusb_context *ctx) usb_api_backend[i].exit(); } exit_dlls(); - exit_polling(); windows_common_exit(); usbi_mutex_destroy(&autoclaim_lock); } @@ -1965,97 +1960,84 @@ void windows_clear_transfer_priv(struct usbi_transfer *itransfer) { struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - usbi_free_fd(&transfer_priv->pollable_fd); + usbi_close(transfer_priv->pollable_fd.fd); + transfer_priv->pollable_fd = INVALID_WINFD; + transfer_priv->handle = NULL; safe_free(transfer_priv->hid_buffer); // When auto claim is in use, attempt to release the auto-claimed interface auto_release(itransfer); } -static int submit_bulk_transfer(struct usbi_transfer *itransfer) +static int do_submit_transfer(struct usbi_transfer *itransfer, short events, + int (*transfer_fn)(int, struct usbi_transfer *)) { - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); + struct libusb_context *ctx = ITRANSFER_CTX(itransfer); struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); + struct winfd wfd; int r; - if (priv->apib->submit_bulk_transfer == NULL) { - PRINT_UNSUPPORTED_API(submit_bulk_transfer); - } + wfd = usbi_create_fd(); + if (wfd.fd < 0) + return LIBUSB_ERROR_NO_MEM; - r = priv->apib->submit_bulk_transfer(SUB_API_NOTSET, itransfer); - if (r != LIBUSB_SUCCESS) + r = usbi_add_pollfd(ctx, wfd.fd, events); + if (r) { + usbi_close(wfd.fd); return r; - - usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, - (short)(IS_XFERIN(transfer) ? POLLIN : POLLOUT)); - - return LIBUSB_SUCCESS; -} - -static int submit_iso_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_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - int r; - - if (priv->apib->submit_iso_transfer == NULL) { - PRINT_UNSUPPORTED_API(submit_iso_transfer); } - r = priv->apib->submit_iso_transfer(SUB_API_NOTSET, itransfer); - if (r != LIBUSB_SUCCESS) - return r; - - usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, - (short)(IS_XFERIN(transfer) ? POLLIN : POLLOUT)); - - return LIBUSB_SUCCESS; -} + // Use transfer_priv to store data needed for async polling + transfer_priv->pollable_fd = wfd; -static int 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_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - int r; + r = transfer_fn(SUB_API_NOTSET, itransfer); - if (priv->apib->submit_control_transfer == NULL) { - PRINT_UNSUPPORTED_API(submit_control_transfer); + if ((r != LIBUSB_SUCCESS) && (r != LIBUSB_ERROR_OVERFLOW)) { + usbi_remove_pollfd(ctx, wfd.fd); + usbi_close(wfd.fd); + transfer_priv->pollable_fd = INVALID_WINFD; } - r = priv->apib->submit_control_transfer(SUB_API_NOTSET, itransfer); - if (r != LIBUSB_SUCCESS) - return r; - - usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, POLLIN); - - return LIBUSB_SUCCESS; + return r; } static int windows_submit_transfer(struct usbi_transfer *itransfer) { struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); + int (*transfer_fn)(int, struct usbi_transfer *); + short events; switch (transfer->type) { case LIBUSB_TRANSFER_TYPE_CONTROL: - return submit_control_transfer(itransfer); + events = (transfer->buffer[0] & LIBUSB_ENDPOINT_IN) ? POLLIN : POLLOUT; + transfer_fn = priv->apib->submit_control_transfer; + break; case LIBUSB_TRANSFER_TYPE_BULK: case LIBUSB_TRANSFER_TYPE_INTERRUPT: if (IS_XFEROUT(transfer) && (transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET)) return LIBUSB_ERROR_NOT_SUPPORTED; - return submit_bulk_transfer(itransfer); + events = IS_XFERIN(transfer) ? POLLIN : POLLOUT; + transfer_fn = priv->apib->submit_bulk_transfer; + break; case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: - return submit_iso_transfer(itransfer); + events = IS_XFERIN(transfer) ? POLLIN : POLLOUT; + transfer_fn = priv->apib->submit_iso_transfer; + break; case LIBUSB_TRANSFER_TYPE_BULK_STREAM: return LIBUSB_ERROR_NOT_SUPPORTED; default: usbi_err(TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type); return LIBUSB_ERROR_INVALID_PARAM; } + + if (transfer_fn == NULL) { + usbi_warn(TRANSFER_CTX(transfer), + "unsupported transfer type %d (unrecognized device driver)", + transfer->type); + return LIBUSB_ERROR_NOT_SUPPORTED; + } + + return do_submit_transfer(itransfer, events, transfer_fn); } static int windows_abort_control(struct usbi_transfer *itransfer) @@ -2108,18 +2090,21 @@ int windows_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size return priv->apib->copy_transfer_data(SUB_API_NOTSET, itransfer, io_size); } -struct winfd *windows_get_fd(struct usbi_transfer *transfer) +int windows_get_transfer_fd(struct usbi_transfer *itransfer) { - struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(transfer); - return &transfer_priv->pollable_fd; + struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); + return transfer_priv->pollable_fd.fd; } -void windows_get_overlapped_result(struct usbi_transfer *transfer, struct winfd *pollable_fd, DWORD *io_result, DWORD *io_size) +void windows_get_overlapped_result(struct usbi_transfer *itransfer, DWORD *io_result, DWORD *io_size) { + struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); + struct winfd *pollable_fd = &transfer_priv->pollable_fd; + if (HasOverlappedIoCompletedSync(pollable_fd->overlapped)) { *io_result = NO_ERROR; *io_size = (DWORD)pollable_fd->overlapped->InternalHigh; - } else if (GetOverlappedResult(pollable_fd->handle, pollable_fd->overlapped, io_size, false)) { + } else if (GetOverlappedResult(transfer_priv->handle, pollable_fd->overlapped, io_size, FALSE)) { // Regular async overlapped *io_result = NO_ERROR; } else { @@ -2669,15 +2654,14 @@ static int winusbx_submit_control_transfer(int sub_api, struct usbi_transfer *it struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); struct windows_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); - WINUSB_SETUP_PACKET *setup = (WINUSB_SETUP_PACKET *)transfer->buffer; + PWINUSB_SETUP_PACKET setup = (PWINUSB_SETUP_PACKET)transfer->buffer; ULONG size; HANDLE winusb_handle; + OVERLAPPED *overlapped; int current_interface; - struct winfd wfd; CHECK_WINUSBX_AVAILABLE(sub_api); - transfer_priv->pollable_fd = INVALID_WINFD; size = transfer->length - LIBUSB_CONTROL_SETUP_SIZE; // Windows places upper limits on the control transfer size @@ -2692,38 +2676,29 @@ static int winusbx_submit_control_transfer(int sub_api, struct usbi_transfer *it } usbi_dbg("will use interface %d", current_interface); - winusb_handle = handle_priv->interface_handle[current_interface].api_handle; - wfd = usbi_create_fd(winusb_handle, RW_READ, NULL, NULL); - // Always use the handle returned from usbi_create_fd (wfd.handle) - if (wfd.fd < 0) - return LIBUSB_ERROR_NO_MEM; + transfer_priv->handle = winusb_handle = handle_priv->interface_handle[current_interface].api_handle; + overlapped = transfer_priv->pollable_fd.overlapped; // Sending of set configuration control requests from WinUSB creates issues if ((LIBUSB_REQ_TYPE(setup->RequestType) == 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); return LIBUSB_ERROR_INVALID_PARAM; } - wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY; - wfd.overlapped->InternalHigh = 0; + windows_force_sync_completion(overlapped, 0); } else { - if (!WinUSBX[sub_api].ControlTransfer(wfd.handle, *setup, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, size, NULL, wfd.overlapped)) { + if (!WinUSBX[sub_api].ControlTransfer(winusb_handle, *setup, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, size, NULL, overlapped)) { if (GetLastError() != ERROR_IO_PENDING) { usbi_warn(ctx, "ControlTransfer failed: %s", windows_error_str(0)); - usbi_free_fd(&wfd); return LIBUSB_ERROR_IO; } } else { - wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY; - wfd.overlapped->InternalHigh = (DWORD)size; + windows_force_sync_completion(overlapped, size); } } - // Use priv_transfer to store data needed for async polling - transfer_priv->pollable_fd = wfd; transfer_priv->interface_number = (uint8_t)current_interface; return LIBUSB_SUCCESS; @@ -2763,14 +2738,12 @@ static int winusbx_submit_bulk_transfer(int sub_api, struct usbi_transfer *itran struct windows_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); HANDLE winusb_handle; + OVERLAPPED *overlapped; bool ret; int current_interface; - struct winfd wfd; CHECK_WINUSBX_AVAILABLE(sub_api); - transfer_priv->pollable_fd = INVALID_WINFD; - current_interface = 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"); @@ -2779,33 +2752,26 @@ static int winusbx_submit_bulk_transfer(int sub_api, struct usbi_transfer *itran usbi_dbg("matched endpoint %02X with interface %d", transfer->endpoint, current_interface); - winusb_handle = handle_priv->interface_handle[current_interface].api_handle; - - wfd = usbi_create_fd(winusb_handle, IS_XFERIN(transfer) ? RW_READ : RW_WRITE, NULL, NULL); - // Always use the handle returned from usbi_create_fd (wfd.handle) - if (wfd.fd < 0) - return LIBUSB_ERROR_NO_MEM; + transfer_priv->handle = winusb_handle = handle_priv->interface_handle[current_interface].api_handle; + overlapped = transfer_priv->pollable_fd.overlapped; if (IS_XFERIN(transfer)) { usbi_dbg("reading %d bytes", transfer->length); - ret = WinUSBX[sub_api].ReadPipe(wfd.handle, transfer->endpoint, transfer->buffer, transfer->length, NULL, wfd.overlapped); + ret = WinUSBX[sub_api].ReadPipe(winusb_handle, transfer->endpoint, transfer->buffer, transfer->length, NULL, overlapped); } else { usbi_dbg("writing %d bytes", transfer->length); - ret = WinUSBX[sub_api].WritePipe(wfd.handle, transfer->endpoint, transfer->buffer, transfer->length, NULL, wfd.overlapped); + ret = WinUSBX[sub_api].WritePipe(winusb_handle, transfer->endpoint, transfer->buffer, transfer->length, NULL, overlapped); } if (!ret) { if (GetLastError() != ERROR_IO_PENDING) { usbi_err(ctx, "ReadPipe/WritePipe failed: %s", windows_error_str(0)); - usbi_free_fd(&wfd); return LIBUSB_ERROR_IO; } } else { - wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY; - wfd.overlapped->InternalHigh = (DWORD)transfer->length; + windows_force_sync_completion(overlapped, (ULONG)transfer->length); } - transfer_priv->pollable_fd = wfd; transfer_priv->interface_number = (uint8_t)current_interface; return LIBUSB_SUCCESS; @@ -2857,7 +2823,7 @@ static int winusbx_abort_transfers(int sub_api, struct usbi_transfer *itransfer) struct windows_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - HANDLE winusb_handle; + HANDLE handle; int current_interface; CHECK_WINUSBX_AVAILABLE(sub_api); @@ -2869,11 +2835,23 @@ static int winusbx_abort_transfers(int sub_api, struct usbi_transfer *itransfer) } usbi_dbg("will use interface %d", current_interface); - winusb_handle = handle_priv->interface_handle[current_interface].api_handle; + handle = handle_priv->interface_handle[current_interface].dev_handle; - if (!WinUSBX[sub_api].AbortPipe(winusb_handle, transfer->endpoint)) { - usbi_err(ctx, "AbortPipe failed: %s", windows_error_str(0)); - return LIBUSB_ERROR_NO_DEVICE; + if (pCancelIoEx != NULL) { + // Use CancelIoEx if available to cancel just a single transfer + if (!pCancelIoEx(handle, transfer_priv->pollable_fd.overlapped)) { + usbi_err(ctx, "CancelIoEx failed: %s", windows_error_str(0)); + return LIBUSB_ERROR_NO_DEVICE; + } + } else { + if (!CancelIo(handle)) { + usbi_err(ctx, "CancelIo failed: %s", windows_error_str(0)); + handle = handle_priv->interface_handle[current_interface].api_handle; + if (!WinUSBX[sub_api].AbortPipe(handle, transfer->endpoint)) { + usbi_err(ctx, "AbortPipe failed: %s", windows_error_str(0)); + return LIBUSB_ERROR_NO_DEVICE; + } + } } return LIBUSB_SUCCESS; @@ -2893,7 +2871,6 @@ static int winusbx_reset_device(int sub_api, struct libusb_device_handle *dev_ha struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); struct windows_device_priv *priv = _device_priv(dev_handle->dev); - struct winfd wfd; HANDLE winusb_handle; int i, j; @@ -2902,13 +2879,6 @@ static int winusbx_reset_device(int sub_api, struct libusb_device_handle *dev_ha // Reset any available pipe (except control) for (i = 0; i < USB_MAXINTERFACES; i++) { winusb_handle = handle_priv->interface_handle[i].api_handle; - for (wfd = handle_to_winfd(winusb_handle); wfd.fd > 0; ) { - // Cancel any pollable I/O - usbi_remove_pollfd(ctx, wfd.fd); - usbi_free_fd(&wfd); - wfd = handle_to_winfd(winusb_handle); - } - if (HANDLE_VALID(winusb_handle)) { for (j = 0; j < priv->usb_interface[i].nb_endpoints; j++) { usbi_dbg("resetting ep %02X", priv->usb_interface[i].endpoint[j]); @@ -3678,14 +3648,13 @@ static int hid_submit_control_transfer(int sub_api, struct usbi_transfer *itrans struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); WINUSB_SETUP_PACKET *setup = (WINUSB_SETUP_PACKET *)transfer->buffer; HANDLE hid_handle; - struct winfd wfd; + OVERLAPPED *overlapped; int current_interface, config; size_t size; int r = LIBUSB_ERROR_INVALID_PARAM; CHECK_HID_AVAILABLE; - transfer_priv->pollable_fd = INVALID_WINFD; safe_free(transfer_priv->hid_buffer); transfer_priv->hid_dest = NULL; size = transfer->length - LIBUSB_CONTROL_SETUP_SIZE; @@ -3700,17 +3669,15 @@ static int hid_submit_control_transfer(int sub_api, struct usbi_transfer *itrans } usbi_dbg("will use interface %d", current_interface); + hid_handle = handle_priv->interface_handle[current_interface].api_handle; - // Always use the handle returned from usbi_create_fd (wfd.handle) - wfd = usbi_create_fd(hid_handle, RW_READ, NULL, NULL); - if (wfd.fd < 0) - return LIBUSB_ERROR_NOT_FOUND; + overlapped = transfer_priv->pollable_fd.overlapped; switch (LIBUSB_REQ_TYPE(setup->RequestType)) { case LIBUSB_REQUEST_TYPE_STANDARD: switch (setup->Request) { case LIBUSB_REQUEST_GET_DESCRIPTOR: - r = _hid_get_descriptor(priv->hid, wfd.handle, LIBUSB_REQ_RECIPIENT(setup->RequestType), + r = _hid_get_descriptor(priv->hid, hid_handle, LIBUSB_REQ_RECIPIENT(setup->RequestType), (setup->Value >> 8) & 0xFF, setup->Value & 0xFF, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, &size); break; case LIBUSB_REQUEST_GET_CONFIGURATION: @@ -3741,39 +3708,31 @@ static int hid_submit_control_transfer(int sub_api, struct usbi_transfer *itrans break; default: usbi_warn(ctx, "unsupported HID control request"); - r = LIBUSB_ERROR_NOT_SUPPORTED; - break; + return LIBUSB_ERROR_NOT_SUPPORTED; } break; case LIBUSB_REQUEST_TYPE_CLASS: - r = _hid_class_request(priv->hid, wfd.handle, setup->RequestType, setup->Request, setup->Value, + r = _hid_class_request(priv->hid, hid_handle, setup->RequestType, setup->Request, setup->Value, setup->Index, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, transfer_priv, - &size, wfd.overlapped); + &size, overlapped); break; default: usbi_warn(ctx, "unsupported HID control request"); - r = LIBUSB_ERROR_NOT_SUPPORTED; - break; + return LIBUSB_ERROR_NOT_SUPPORTED; } + if (r < 0) + return r; + if (r == LIBUSB_COMPLETED) { // Force request to be completed synchronously. Transferred size has been set by previous call - wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY; - // http://msdn.microsoft.com/en-us/library/ms684342%28VS.85%29.aspx - // set InternalHigh to the number of bytes transferred - wfd.overlapped->InternalHigh = (DWORD)size; + windows_force_sync_completion(overlapped, (ULONG)size); r = LIBUSB_SUCCESS; } - if (r == LIBUSB_SUCCESS) { - // Use priv_transfer to store data needed for async polling - transfer_priv->pollable_fd = wfd; - transfer_priv->interface_number = (uint8_t)current_interface; - } else { - usbi_free_fd(&wfd); - } + transfer_priv->interface_number = (uint8_t)current_interface; - return r; + return LIBUSB_SUCCESS; } static int hid_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer) @@ -3783,8 +3742,8 @@ static int hid_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); struct windows_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - struct winfd wfd; HANDLE hid_handle; + OVERLAPPED *overlapped; bool direction_in, ret; int current_interface, length; DWORD size; @@ -3792,7 +3751,6 @@ static int hid_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer CHECK_HID_AVAILABLE; - transfer_priv->pollable_fd = INVALID_WINFD; transfer_priv->hid_dest = NULL; safe_free(transfer_priv->hid_buffer); @@ -3804,13 +3762,9 @@ static int hid_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer usbi_dbg("matched endpoint %02X with interface %d", transfer->endpoint, current_interface); - hid_handle = handle_priv->interface_handle[current_interface].api_handle; - direction_in = transfer->endpoint & LIBUSB_ENDPOINT_IN; - - wfd = usbi_create_fd(hid_handle, direction_in?RW_READ:RW_WRITE, NULL, NULL); - // Always use the handle returned from usbi_create_fd (wfd.handle) - if (wfd.fd < 0) - return LIBUSB_ERROR_NO_MEM; + transfer_priv->handle = hid_handle = handle_priv->interface_handle[current_interface].api_handle; + overlapped = transfer_priv->pollable_fd.overlapped; + direction_in = IS_XFERIN(transfer); // If report IDs are not in use, an extra prefix byte must be added if (((direction_in) && (!priv->hid->uses_report_ids[0])) @@ -3829,7 +3783,7 @@ static int hid_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer if (direction_in) { transfer_priv->hid_dest = transfer->buffer; usbi_dbg("reading %d bytes (report ID: 0x00)", length); - ret = ReadFile(wfd.handle, transfer_priv->hid_buffer, length + 1, &size, wfd.overlapped); + ret = ReadFile(hid_handle, transfer_priv->hid_buffer, length + 1, &size, overlapped); } else { if (!priv->hid->uses_report_ids[1]) memcpy(transfer_priv->hid_buffer + 1, transfer->buffer, transfer->length); @@ -3838,13 +3792,12 @@ static int hid_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer memcpy(transfer_priv->hid_buffer, transfer->buffer, transfer->length); usbi_dbg("writing %d bytes (report ID: 0x%02X)", length, transfer_priv->hid_buffer[0]); - ret = WriteFile(wfd.handle, transfer_priv->hid_buffer, length, &size, wfd.overlapped); + ret = WriteFile(hid_handle, transfer_priv->hid_buffer, length, &size, overlapped); } if (!ret) { if (GetLastError() != ERROR_IO_PENDING) { usbi_err(ctx, "HID transfer failed: %s", windows_error_str(0)); - usbi_free_fd(&wfd); safe_free(transfer_priv->hid_buffer); return LIBUSB_ERROR_IO; } @@ -3862,11 +3815,9 @@ static int hid_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer usbi_err(ctx, "OVERFLOW!"); r = LIBUSB_ERROR_OVERFLOW; } - wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY; - wfd.overlapped->InternalHigh = size; + windows_force_sync_completion(overlapped, (ULONG)size); } - transfer_priv->pollable_fd = wfd; transfer_priv->interface_number = (uint8_t)current_interface; return r; @@ -3874,6 +3825,7 @@ static int hid_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer static int hid_abort_transfers(int sub_api, struct usbi_transfer *itransfer) { + struct libusb_context *ctx = ITRANSFER_CTX(itransfer); struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); struct windows_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); @@ -3883,10 +3835,25 @@ static int hid_abort_transfers(int sub_api, struct usbi_transfer *itransfer) CHECK_HID_AVAILABLE; current_interface = transfer_priv->interface_number; - hid_handle = handle_priv->interface_handle[current_interface].api_handle; - CancelIo(hid_handle); + if ((current_interface < 0) || (current_interface >= USB_MAXINTERFACES)) { + usbi_err(ctx, "program assertion failed: invalid interface_number"); + return LIBUSB_ERROR_NOT_FOUND; + } + usbi_dbg("will use interface %d", current_interface); - return LIBUSB_SUCCESS; + hid_handle = handle_priv->interface_handle[current_interface].dev_handle; + + if (pCancelIoEx != NULL) { + // Use CancelIoEx if available to cancel just a single transfer + if (pCancelIoEx(hid_handle, transfer_priv->pollable_fd.overlapped)) + return LIBUSB_SUCCESS; + } else { + if (CancelIo(hid_handle)) + return LIBUSB_SUCCESS; + } + + usbi_warn(ctx, "cancel failed: %s", windows_error_str(0)); + return LIBUSB_ERROR_NOT_FOUND; } static int hid_reset_device(int sub_api, struct libusb_device_handle *dev_handle) @@ -4187,9 +4154,15 @@ static int composite_abort_control(int sub_api, struct usbi_transfer *itransfer) struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); + int current_interface = transfer_priv->interface_number; - return priv->usb_interface[transfer_priv->interface_number].apib-> - abort_control(priv->usb_interface[transfer_priv->interface_number].sub_api, itransfer); + if ((current_interface < 0) || (current_interface >= USB_MAXINTERFACES)) { + usbi_err(TRANSFER_CTX(transfer), "program assertion failed: invalid interface_number"); + return LIBUSB_ERROR_NOT_FOUND; + } + + return priv->usb_interface[current_interface].apib-> + abort_control(priv->usb_interface[current_interface].sub_api, itransfer); } static int composite_abort_transfers(int sub_api, struct usbi_transfer *itransfer) @@ -4197,9 +4170,15 @@ static int composite_abort_transfers(int sub_api, struct usbi_transfer *itransfe struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); + int current_interface = transfer_priv->interface_number; - return priv->usb_interface[transfer_priv->interface_number].apib-> - abort_transfers(priv->usb_interface[transfer_priv->interface_number].sub_api, itransfer); + if ((current_interface < 0) || (current_interface >= USB_MAXINTERFACES)) { + usbi_err(TRANSFER_CTX(transfer), "program assertion failed: invalid interface_number"); + return LIBUSB_ERROR_NOT_FOUND; + } + + return priv->usb_interface[current_interface].apib-> + abort_transfers(priv->usb_interface[current_interface].sub_api, itransfer); } static int composite_reset_device(int sub_api, struct libusb_device_handle *dev_handle) |