diff options
-rw-r--r-- | libusb/os/poll_windows.c | 3 | ||||
-rw-r--r-- | libusb/os/poll_windows.h | 7 | ||||
-rw-r--r-- | libusb/os/windows_common.c | 268 | ||||
-rw-r--r-- | libusb/os/windows_common.h | 58 | ||||
-rw-r--r-- | libusb/os/windows_usbdk.c | 224 | ||||
-rw-r--r-- | libusb/os/windows_winusb.c | 1215 | ||||
-rw-r--r-- | libusb/os/windows_winusb.h | 158 | ||||
-rw-r--r-- | libusb/version_nano.h | 2 |
8 files changed, 829 insertions, 1106 deletions
diff --git a/libusb/os/poll_windows.c b/libusb/os/poll_windows.c index f735245..490ee7f 100644 --- a/libusb/os/poll_windows.c +++ b/libusb/os/poll_windows.c @@ -392,8 +392,7 @@ int usbi_poll(struct pollfd *fds, usbi_nfds_t nfds, int timeout) if (fd == NULL) { fds[n].revents = POLLNVAL; nready++; - } else if (HasOverlappedIoCompleted(&fd->overlapped) && - (WaitForSingleObject(fd->overlapped.hEvent, 0) == WAIT_OBJECT_0)) { + } else if (HasOverlappedIoCompleted(&fd->overlapped)) { fds[n].revents = fds[n].events; nready++; } else { diff --git a/libusb/os/poll_windows.h b/libusb/os/poll_windows.h index b2c94f9..a38e1da 100644 --- a/libusb/os/poll_windows.h +++ b/libusb/os/poll_windows.h @@ -25,13 +25,6 @@ #ifndef LIBUSB_POLL_WINDOWS_H #define LIBUSB_POLL_WINDOWS_H -// Handle synchronous completion through the overlapped structure -#if !defined(STATUS_REPARSE) // reuse the REPARSE status code -#define STATUS_REPARSE ((LONG)0x00000104L) -#endif -#define STATUS_COMPLETED_SYNCHRONOUSLY STATUS_REPARSE -#define HasOverlappedIoCompletedSync(lpOverlapped) (((DWORD)(lpOverlapped)->Internal) == STATUS_COMPLETED_SYNCHRONOUSLY) - #define DUMMY_HANDLE ((HANDLE)(LONG_PTR)-2) #define POLLIN 0x0001 /* There is data to read */ diff --git a/libusb/os/windows_common.c b/libusb/os/windows_common.c index a2c9beb..3a11c56 100644 --- a/libusb/os/windows_common.c +++ b/libusb/os/windows_common.c @@ -33,12 +33,14 @@ #define EPOCH_TIME UINT64_C(116444736000000000) // 1970.01.01 00:00:000 in MS Filetime +#define STATUS_SUCCESS ((ULONG_PTR)0UL) + // Public enum windows_version windows_version = WINDOWS_UNDEFINED; // Global variables for init/exit -static unsigned int init_count = 0; -static bool usbdk_available = false; +static unsigned int init_count; +static bool usbdk_available; // Global variables for clock_gettime mechanism static uint64_t hires_ticks_to_ps; @@ -114,7 +116,7 @@ typedef struct htab_entry { char *str; } htab_entry; -static htab_entry *htab_table = NULL; +static htab_entry *htab_table; static usbi_mutex_t htab_mutex; static unsigned long htab_filled; @@ -125,7 +127,7 @@ static unsigned long htab_filled; static bool htab_create(struct libusb_context *ctx) { if (htab_table != NULL) { - usbi_err(ctx, "hash table already allocated"); + usbi_err(ctx, "program assertion falied - hash table already allocated"); return true; } @@ -173,7 +175,7 @@ unsigned long htab_hash(const char *str) { unsigned long hval, hval2; unsigned long idx; - unsigned long r = 5381; + unsigned long r = 5381UL; int c; const char *sz = str; @@ -204,7 +206,7 @@ unsigned long htab_hash(const char *str) usbi_dbg("hash collision ('%s' vs '%s')", str, htab_table[idx].str); // Second hash function, as suggested in [Knuth] - hval2 = 1 + hval % (HTAB_SIZE - 2); + hval2 = 1UL + hval % (HTAB_SIZE - 2); do { // Because size is prime this guarantees to step through all available indexes @@ -228,14 +230,14 @@ unsigned long htab_hash(const char *str) // If the table is full return an error if (htab_filled >= HTAB_SIZE) { usbi_err(NULL, "hash table is full (%lu entries)", HTAB_SIZE); - idx = 0; + idx = 0UL; goto out_unlock; } htab_table[idx].str = _strdup(str); if (htab_table[idx].str == NULL) { usbi_err(NULL, "could not duplicate string for hash table"); - idx = 0; + idx = 0UL; goto out_unlock; } @@ -248,13 +250,33 @@ out_unlock: return idx; } +enum libusb_transfer_status usbd_status_to_libusb_transfer_status(USBD_STATUS status) +{ + if (USBD_SUCCESS(status)) + return LIBUSB_TRANSFER_COMPLETED; + + switch (status) { + case USBD_STATUS_TIMEOUT: + return LIBUSB_TRANSFER_TIMED_OUT; + case USBD_STATUS_CANCELED: + return LIBUSB_TRANSFER_CANCELLED; + case USBD_STATUS_ENDPOINT_HALTED: + return LIBUSB_TRANSFER_STALL; + case USBD_STATUS_DEVICE_GONE: + return LIBUSB_TRANSFER_NO_DEVICE; + default: + usbi_dbg("USBD_STATUS 0x%08lx translated to LIBUSB_TRANSFER_ERROR", ULONG_CAST(status)); + return LIBUSB_TRANSFER_ERROR; + } +} + /* * Make a transfer complete synchronously */ void windows_force_sync_completion(OVERLAPPED *overlapped, ULONG size) { - overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY; - overlapped->InternalHigh = size; + overlapped->Internal = (ULONG_PTR)STATUS_SUCCESS; + overlapped->InternalHigh = (ULONG_PTR)size; SetEvent(overlapped->hEvent); } @@ -294,7 +316,7 @@ static void get_windows_version(void) const char *arch, *w = NULL; unsigned major, minor, version; ULONGLONG major_equal, minor_equal; - BOOL ws; + bool ws; windows_version = WINDOWS_UNDEFINED; @@ -378,16 +400,17 @@ static void get_windows_version(void) } static void windows_transfer_callback(const struct windows_backend *backend, - struct usbi_transfer *itransfer, DWORD io_result, DWORD io_size) + struct usbi_transfer *itransfer, DWORD error, DWORD bytes_transferred) { - int status, istatus; + struct windows_transfer_priv *transfer_priv = get_transfer_priv(itransfer); + enum libusb_transfer_status status, istatus; - usbi_dbg("handling I/O completion with errcode %lu, size %lu", - ULONG_CAST(io_result), ULONG_CAST(io_size)); + usbi_dbg("handling I/O completion with errcode %lu, length %lu", + ULONG_CAST(error), ULONG_CAST(bytes_transferred)); - switch (io_result) { + switch (error) { case NO_ERROR: - status = backend->copy_transfer_data(itransfer, (uint32_t)io_size); + status = backend->copy_transfer_data(itransfer, bytes_transferred); break; case ERROR_GEN_FAILURE: usbi_dbg("detected endpoint stall"); @@ -398,9 +421,9 @@ static void windows_transfer_callback(const struct windows_backend *backend, status = LIBUSB_TRANSFER_TIMED_OUT; break; case ERROR_OPERATION_ABORTED: - istatus = backend->copy_transfer_data(itransfer, (uint32_t)io_size); + istatus = backend->copy_transfer_data(itransfer, bytes_transferred); if (istatus != LIBUSB_TRANSFER_COMPLETED) - usbi_dbg("Failed to copy partial data in aborted operation: %d", istatus); + usbi_dbg("failed to copy partial data in aborted operation: %d", (int)istatus); usbi_dbg("detected operation aborted"); status = LIBUSB_TRANSFER_CANCELLED; @@ -412,57 +435,45 @@ static void windows_transfer_callback(const struct windows_backend *backend, break; default: usbi_err(ITRANSFER_CTX(itransfer), "detected I/O error %lu: %s", - ULONG_CAST(io_result), windows_error_str(io_result)); + ULONG_CAST(error), windows_error_str(error)); status = LIBUSB_TRANSFER_ERROR; break; } - backend->clear_transfer_priv(itransfer); // Cancel polling + + // Cancel polling + usbi_close(transfer_priv->pollable_fd.fd); + transfer_priv->pollable_fd = INVALID_WINFD; + transfer_priv->handle = NULL; + + // Backend-specific cleanup + backend->clear_transfer_priv(itransfer); + if (status == LIBUSB_TRANSFER_CANCELLED) usbi_handle_transfer_cancellation(itransfer); else - usbi_handle_transfer_completion(itransfer, (enum libusb_transfer_status)status); -} - -static void windows_handle_callback(const struct windows_backend *backend, - struct usbi_transfer *itransfer, DWORD io_result, DWORD io_size) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - - switch (transfer->type) { - case LIBUSB_TRANSFER_TYPE_CONTROL: - case LIBUSB_TRANSFER_TYPE_BULK: - case LIBUSB_TRANSFER_TYPE_INTERRUPT: - case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: - windows_transfer_callback(backend, itransfer, io_result, io_size); - break; - case LIBUSB_TRANSFER_TYPE_BULK_STREAM: - usbi_warn(ITRANSFER_CTX(itransfer), "bulk stream transfers are not yet supported on this platform"); - break; - default: - usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type); - } + usbi_handle_transfer_completion(itransfer, status); } static int windows_init(struct libusb_context *ctx) { struct windows_context_priv *priv = _context_priv(ctx); - HANDLE semaphore; - char sem_name[11 + 8 + 1]; // strlen("libusb_init") + (32-bit hex PID) + '\0' + char mutex_name[11 + 8 + 1]; // strlen("libusb_init") + (32-bit hex PID) + '\0' + HANDLE mutex; int r = LIBUSB_ERROR_OTHER; bool winusb_backend_init = false; - sprintf(sem_name, "libusb_init%08X", (unsigned int)(GetCurrentProcessId() & 0xFFFFFFFF)); - semaphore = CreateSemaphoreA(NULL, 1, 1, sem_name); - if (semaphore == NULL) { - usbi_err(ctx, "could not create semaphore: %s", windows_error_str(0)); + sprintf(mutex_name, "libusb_init%08X", (unsigned int)(GetCurrentProcessId() & 0xFFFFFFFFU)); + mutex = CreateMutexA(NULL, FALSE, mutex_name); + if (mutex == NULL) { + usbi_err(ctx, "could not create mutex: %s", windows_error_str(0)); return LIBUSB_ERROR_NO_MEM; } - // A successful wait brings our semaphore count to 0 (unsignaled) - // => any concurent wait stalls until the semaphore's release - if (WaitForSingleObject(semaphore, INFINITE) != WAIT_OBJECT_0) { - usbi_err(ctx, "failure to access semaphore: %s", windows_error_str(0)); - CloseHandle(semaphore); + // A successful wait gives this thread ownership of the mutex + // => any concurent wait stalls until the mutex is released + if (WaitForSingleObject(mutex, INFINITE) != WAIT_OBJECT_0) { + usbi_err(ctx, "failure to access mutex: %s", windows_error_str(0)); + CloseHandle(mutex); return LIBUSB_ERROR_NO_MEM; } @@ -511,26 +522,26 @@ init_exit: // Holds semaphore here --init_count; } - ReleaseSemaphore(semaphore, 1, NULL); // increase count back to 1 - CloseHandle(semaphore); + ReleaseMutex(mutex); + CloseHandle(mutex); return r; } static void windows_exit(struct libusb_context *ctx) { - HANDLE semaphore; - char sem_name[11 + 8 + 1]; // strlen("libusb_init") + (32-bit hex PID) + '\0' - UNUSED(ctx); + char mutex_name[11 + 8 + 1]; // strlen("libusb_init") + (32-bit hex PID) + '\0' + HANDLE mutex; - sprintf(sem_name, "libusb_init%08lX", (GetCurrentProcessId() & 0xFFFFFFFFUL)); - semaphore = CreateSemaphoreA(NULL, 1, 1, sem_name); - if (semaphore == NULL) + sprintf(mutex_name, "libusb_init%08lX", (GetCurrentProcessId() & 0xFFFFFFFFU)); + mutex = CreateMutexA(NULL, FALSE, mutex_name); + if (mutex == NULL) return; - // A successful wait brings our semaphore count to 0 (unsignaled) - // => any concurent wait stalls until the semaphore release - if (WaitForSingleObject(semaphore, INFINITE) != WAIT_OBJECT_0) { - CloseHandle(semaphore); + // A successful wait gives this thread ownership of the mutex + // => any concurent wait stalls until the mutex is released + if (WaitForSingleObject(mutex, INFINITE) != WAIT_OBJECT_0) { + usbi_err(ctx, "failed to access mutex: %s", windows_error_str(0)); + CloseHandle(mutex); return; } @@ -544,8 +555,8 @@ static void windows_exit(struct libusb_context *ctx) htab_destroy(); } - ReleaseSemaphore(semaphore, 1, NULL); // increase count back to 1 - CloseHandle(semaphore); + ReleaseMutex(mutex); + CloseHandle(mutex); } static int windows_set_option(struct libusb_context *ctx, enum libusb_option option, va_list ap) @@ -567,7 +578,6 @@ static int windows_set_option(struct libusb_context *ctx, enum libusb_option opt default: return LIBUSB_ERROR_NOT_SUPPORTED; } - } static int windows_get_device_list(struct libusb_context *ctx, struct discovered_devs **discdevs) @@ -671,29 +681,103 @@ static void windows_destroy_device(struct libusb_device *dev) static int windows_submit_transfer(struct usbi_transfer *itransfer) { - struct windows_context_priv *priv = _context_priv(ITRANSFER_CTX(itransfer)); - return priv->backend->submit_transfer(itransfer); + struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + struct libusb_context *ctx = TRANSFER_CTX(transfer); + struct windows_context_priv *priv = _context_priv(ctx); + struct windows_transfer_priv *transfer_priv = get_transfer_priv(itransfer); + short events; + int r; + + switch (transfer->type) { + case LIBUSB_TRANSFER_TYPE_CONTROL: + events = (transfer->buffer[0] & LIBUSB_ENDPOINT_IN) ? POLLIN : POLLOUT; + break; + case LIBUSB_TRANSFER_TYPE_BULK: + case LIBUSB_TRANSFER_TYPE_INTERRUPT: + case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: + events = IS_XFERIN(transfer) ? POLLIN : POLLOUT; + break; + case LIBUSB_TRANSFER_TYPE_BULK_STREAM: + usbi_warn(ctx, "bulk stream transfers are not yet supported on this platform"); + return LIBUSB_ERROR_NOT_SUPPORTED; + default: + usbi_err(ctx, "unknown endpoint type %d", transfer->type); + return LIBUSB_ERROR_INVALID_PARAM; + } + + // Because a Windows OVERLAPPED is used for poll emulation, + // a pollable fd is created and stored with each transfer + transfer_priv->pollable_fd = usbi_create_fd(); + if (transfer_priv->pollable_fd.fd < 0) { + usbi_err(ctx, "failed to create pollable fd"); + return LIBUSB_ERROR_NO_MEM; + } + + if (transfer_priv->handle != NULL) { + usbi_err(ctx, "program assertion failed - transfer HANDLE is not NULL"); + transfer_priv->handle = NULL; + } + + r = priv->backend->submit_transfer(itransfer); + if (r != LIBUSB_SUCCESS) { + // Always call the backend's clear_transfer_priv() function on failure + priv->backend->clear_transfer_priv(itransfer); + // Release the pollable fd since it won't be used + usbi_close(transfer_priv->pollable_fd.fd); + transfer_priv->pollable_fd = INVALID_WINFD; + transfer_priv->handle = NULL; + return r; + } + + // The backend should set the HANDLE used for each submitted transfer + // by calling set_transfer_priv_handle() + if (transfer_priv->handle == NULL) + usbi_err(ctx, "program assertion failed - transfer HANDLE is NULL after transfer was submitted"); + + // We don't want to start monitoring the pollable fd before the transfer + // has been submitted, so start monitoring it now. Note that if the + // usbi_add_pollfd() function fails, the user will never get notified + // that the transfer has completed. We don't attempt any cleanup if this + // happens because the transfer is already in progress and could even have + // completed + if (usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, events)) + usbi_err(ctx, "failed to add pollable fd %d for transfer %p", + transfer_priv->pollable_fd.fd, transfer); + + return r; } static int windows_cancel_transfer(struct usbi_transfer *itransfer) { struct windows_context_priv *priv = _context_priv(ITRANSFER_CTX(itransfer)); - return priv->backend->cancel_transfer(itransfer); + struct windows_transfer_priv *transfer_priv = get_transfer_priv(itransfer); + + // Try CancelIoEx() on the transfer + // If that fails, fall back to the backend's cancel_transfer() + // function if it is available + if (CancelIoEx(transfer_priv->handle, transfer_priv->pollable_fd.overlapped)) + return LIBUSB_SUCCESS; + else if (GetLastError() == ERROR_NOT_FOUND) + return LIBUSB_ERROR_NOT_FOUND; + + if (priv->backend->cancel_transfer) + return priv->backend->cancel_transfer(itransfer); + + usbi_warn(ITRANSFER_CTX(itransfer), "cancellation not supported for this transfer's driver"); + return LIBUSB_ERROR_NOT_SUPPORTED; } static int windows_handle_events(struct libusb_context *ctx, struct pollfd *fds, usbi_nfds_t nfds, int num_ready) { struct windows_context_priv *priv = _context_priv(ctx); struct usbi_transfer *itransfer; - DWORD io_size, io_result; + struct windows_transfer_priv *transfer_priv; + DWORD result, bytes_transferred; usbi_nfds_t i; - bool found; - int transfer_fd; int r = LIBUSB_SUCCESS; usbi_mutex_lock(&ctx->open_devs_lock); for (i = 0; i < nfds && num_ready > 0; i++) { - usbi_dbg("checking fd %d with revents = %04x", fds[i].fd, fds[i].revents); if (!fds[i].revents) @@ -701,34 +785,30 @@ static int windows_handle_events(struct libusb_context *ctx, struct pollfd *fds, num_ready--; - // Because a Windows OVERLAPPED is used for poll emulation, - // a pollable fd is created and stored with each transfer - found = false; - transfer_fd = -1; + transfer_priv = NULL; usbi_mutex_lock(&ctx->flying_transfers_lock); list_for_each_entry(itransfer, &ctx->flying_transfers, list, struct usbi_transfer) { - transfer_fd = priv->backend->get_transfer_fd(itransfer); - if (transfer_fd == fds[i].fd) { - found = true; + transfer_priv = get_transfer_priv(itransfer); + if (transfer_priv->pollable_fd.fd == fds[i].fd) break; - } + transfer_priv = NULL; } usbi_mutex_unlock(&ctx->flying_transfers_lock); - if (found) { - priv->backend->get_overlapped_result(itransfer, &io_result, &io_size); - - usbi_remove_pollfd(ctx, transfer_fd); - - // let handle_callback free the event using the transfer wfd - // If you don't use the transfer wfd, you run a risk of trying to free a - // newly allocated wfd that took the place of the one from the transfer. - windows_handle_callback(priv->backend, itransfer, io_result, io_size); - } else { + if (transfer_priv == NULL) { usbi_err(ctx, "could not find a matching transfer for fd %d", fds[i].fd); r = LIBUSB_ERROR_NOT_FOUND; break; } + + usbi_remove_pollfd(ctx, transfer_priv->pollable_fd.fd); + + if (GetOverlappedResult(transfer_priv->handle, transfer_priv->pollable_fd.overlapped, &bytes_transferred, FALSE)) + result = NO_ERROR; + else + result = GetLastError(); + + windows_transfer_callback(priv->backend, itransfer, result, bytes_transferred); } usbi_mutex_unlock(&ctx->open_devs_lock); @@ -814,5 +894,5 @@ const struct usbi_os_backend usbi_backend = { sizeof(struct windows_context_priv), sizeof(union windows_device_priv), sizeof(union windows_device_handle_priv), - sizeof(union windows_transfer_priv), + sizeof(struct windows_transfer_priv), }; diff --git a/libusb/os/windows_common.h b/libusb/os/windows_common.h index 93ea23e..63d3183 100644 --- a/libusb/os/windows_common.h +++ b/libusb/os/windows_common.h @@ -68,13 +68,13 @@ #define DLL_HANDLE_NAME(name) __dll_##name##_handle #define DLL_DECLARE_HANDLE(name) \ - static HMODULE DLL_HANDLE_NAME(name) = NULL + static HMODULE DLL_HANDLE_NAME(name) #define DLL_GET_HANDLE(name) \ do { \ DLL_HANDLE_NAME(name) = DLL_LOAD_LIBRARY(name); \ if (!DLL_HANDLE_NAME(name)) \ - return FALSE; \ + return false; \ } while (0) #define DLL_FREE_HANDLE(name) \ @@ -92,7 +92,7 @@ #define DLL_DECLARE_FUNC_PREFIXNAME(api, ret, prefixname, name, args) \ typedef ret (api * DLL_FUNC_NAME(name))args; \ - static DLL_FUNC_NAME(name) prefixname = NULL + static DLL_FUNC_NAME(name) prefixname #define DLL_DECLARE_FUNC(api, ret, name, args) \ DLL_DECLARE_FUNC_PREFIXNAME(api, ret, name, name, args) @@ -115,7 +115,7 @@ if (prefixname) \ break; \ if (ret_on_failure) \ - return FALSE; \ + return false; \ } while (0) #define DLL_LOAD_FUNC(dll, name, ret_on_failure) \ @@ -271,16 +271,13 @@ struct winusb_device_handle_priv { struct usbdk_transfer_priv { USB_DK_TRANSFER_REQUEST request; - struct winfd pollable_fd; - HANDLE system_handle; PULONG64 IsochronousPacketsArray; PUSB_DK_ISO_TRANSFER_RESULT IsochronousResultsArray; }; struct winusb_transfer_priv { - struct winfd pollable_fd; - HANDLE handle; uint8_t interface_number; + uint8_t *hid_buffer; // 1 byte extended data buffer, required for HID uint8_t *hid_dest; // transfer buffer destination, required for HID size_t hid_expected_size; @@ -322,10 +319,7 @@ struct windows_backend { int (*submit_transfer)(struct usbi_transfer *itransfer); int (*cancel_transfer)(struct usbi_transfer *itransfer); void (*clear_transfer_priv)(struct usbi_transfer *itransfer); - int (*copy_transfer_data)(struct usbi_transfer *itransfer, uint32_t io_size); - int (*get_transfer_fd)(struct usbi_transfer *itransfer); - void (*get_overlapped_result)(struct usbi_transfer *itransfer, - DWORD *io_result, DWORD *io_size); + enum libusb_transfer_status (*copy_transfer_data)(struct usbi_transfer *itransfer, DWORD length); }; struct windows_context_priv { @@ -342,15 +336,49 @@ union windows_device_handle_priv { struct winusb_device_handle_priv winusb_priv; }; -union windows_transfer_priv { - struct usbdk_transfer_priv usbdk_priv; - struct winusb_transfer_priv winusb_priv; +struct windows_transfer_priv { + struct winfd pollable_fd; + HANDLE handle; + union { + struct usbdk_transfer_priv usbdk_priv; + struct winusb_transfer_priv winusb_priv; + }; }; +static inline struct windows_transfer_priv *get_transfer_priv(struct usbi_transfer *itransfer) +{ + return (struct windows_transfer_priv *)usbi_transfer_get_os_priv(itransfer); +} + +static inline OVERLAPPED *get_transfer_priv_overlapped(struct usbi_transfer *itransfer) +{ + struct windows_transfer_priv *transfer_priv = get_transfer_priv(itransfer); + return transfer_priv->pollable_fd.overlapped; +} + +static inline void set_transfer_priv_handle(struct usbi_transfer *itransfer, HANDLE handle) +{ + struct windows_transfer_priv *transfer_priv = get_transfer_priv(itransfer); + transfer_priv->handle = handle; +} + +static inline struct usbdk_transfer_priv *get_usbdk_transfer_priv(struct usbi_transfer *itransfer) +{ + struct windows_transfer_priv *transfer_priv = get_transfer_priv(itransfer); + return &transfer_priv->usbdk_priv; +} + +static inline struct winusb_transfer_priv *get_winusb_transfer_priv(struct usbi_transfer *itransfer) +{ + struct windows_transfer_priv *transfer_priv = get_transfer_priv(itransfer); + return &transfer_priv->winusb_priv; +} + extern const struct windows_backend usbdk_backend; extern const struct windows_backend winusb_backend; unsigned long htab_hash(const char *str); +enum libusb_transfer_status usbd_status_to_libusb_transfer_status(USBD_STATUS status); void windows_force_sync_completion(OVERLAPPED *overlapped, ULONG size); #if defined(ENABLE_LOGGING) diff --git a/libusb/os/windows_usbdk.c b/libusb/os/windows_usbdk.c index bbec3d8..46935a6 100644 --- a/libusb/os/windows_usbdk.c +++ b/libusb/os/windows_usbdk.c @@ -48,11 +48,6 @@ static inline struct usbdk_device_priv *_usbdk_device_priv(struct libusb_device return (struct usbdk_device_priv *)dev->os_priv; } -static inline struct usbdk_transfer_priv *_usbdk_transfer_priv(struct usbi_transfer *itransfer) -{ - return (struct usbdk_transfer_priv *)usbi_transfer_get_os_priv(itransfer); -} - static struct { HMODULE module; @@ -423,7 +418,7 @@ static int usbdk_open(struct libusb_device_handle *dev_handle) priv->redirector_handle = usbdk_helper.StartRedirect(&priv->info.ID); if (priv->redirector_handle == INVALID_HANDLE_VALUE) { - usbi_err(DEVICE_CTX(dev_handle->dev), "Redirector startup failed"); + usbi_err(HANDLE_CTX(dev_handle), "Redirector startup failed"); return LIBUSB_ERROR_OTHER; } @@ -463,11 +458,10 @@ static int usbdk_claim_interface(struct libusb_device_handle *dev_handle, int if static int usbdk_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting) { - struct libusb_context *ctx = HANDLE_CTX(dev_handle); struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev); if (!usbdk_helper.SetAltsetting(priv->redirector_handle, iface, altsetting)) { - usbi_err(ctx, "SetAltsetting failed: %s", windows_error_str(0)); + usbi_err(HANDLE_CTX(dev_handle), "SetAltsetting failed: %s", windows_error_str(0)); return LIBUSB_ERROR_NO_DEVICE; } @@ -483,11 +477,10 @@ static int usbdk_release_interface(struct libusb_device_handle *dev_handle, int static int usbdk_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint) { - struct libusb_context *ctx = HANDLE_CTX(dev_handle); struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev); if (!usbdk_helper.ResetPipe(priv->redirector_handle, endpoint)) { - usbi_err(ctx, "ResetPipe failed: %s", windows_error_str(0)); + usbi_err(HANDLE_CTX(dev_handle), "ResetPipe failed: %s", windows_error_str(0)); return LIBUSB_ERROR_NO_DEVICE; } @@ -496,11 +489,10 @@ static int usbdk_clear_halt(struct libusb_device_handle *dev_handle, unsigned ch static int usbdk_reset_device(struct libusb_device_handle *dev_handle) { - struct libusb_context *ctx = HANDLE_CTX(dev_handle); struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev); if (!usbdk_helper.ResetDevice(priv->redirector_handle)) { - usbi_err(ctx, "ResetDevice failed: %s", windows_error_str(0)); + usbi_err(HANDLE_CTX(dev_handle), "ResetDevice failed: %s", windows_error_str(0)); return LIBUSB_ERROR_NO_DEVICE; } @@ -517,13 +509,9 @@ static void usbdk_destroy_device(struct libusb_device *dev) static void usbdk_clear_transfer_priv(struct usbi_transfer *itransfer) { - struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer); + struct usbdk_transfer_priv *transfer_priv = get_usbdk_transfer_priv(itransfer); struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - usbi_close(transfer_priv->pollable_fd.fd); - transfer_priv->pollable_fd = INVALID_WINFD; - transfer_priv->system_handle = NULL; - if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) { safe_free(transfer_priv->IsochronousPacketsArray); safe_free(transfer_priv->IsochronousResultsArray); @@ -534,9 +522,8 @@ static int usbdk_do_control_transfer(struct usbi_transfer *itransfer) { struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev); - struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer); - struct libusb_context *ctx = TRANSFER_CTX(transfer); - OVERLAPPED *overlapped = transfer_priv->pollable_fd.overlapped; + struct usbdk_transfer_priv *transfer_priv = get_usbdk_transfer_priv(itransfer); + OVERLAPPED *overlapped = get_transfer_priv_overlapped(itransfer); TransferResult transResult; transfer_priv->request.Buffer = (PVOID64)transfer->buffer; @@ -555,10 +542,12 @@ static int usbdk_do_control_transfer(struct usbi_transfer *itransfer) case TransferSuccessAsync: break; case TransferFailure: - usbi_err(ctx, "ControlTransfer failed: %s", windows_error_str(0)); + usbi_err(TRANSFER_CTX(transfer), "ControlTransfer failed: %s", windows_error_str(0)); return LIBUSB_ERROR_IO; } + set_transfer_priv_handle(itransfer, priv->system_handle); + return LIBUSB_SUCCESS; } @@ -566,9 +555,8 @@ static int usbdk_do_bulk_transfer(struct usbi_transfer *itransfer) { struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev); - struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer); - struct libusb_context *ctx = TRANSFER_CTX(transfer); - OVERLAPPED *overlapped = transfer_priv->pollable_fd.overlapped; + struct usbdk_transfer_priv *transfer_priv = get_usbdk_transfer_priv(itransfer); + OVERLAPPED *overlapped = get_transfer_priv_overlapped(itransfer); TransferResult transferRes; transfer_priv->request.Buffer = (PVOID64)transfer->buffer; @@ -582,9 +570,6 @@ static int usbdk_do_bulk_transfer(struct usbi_transfer *itransfer) case LIBUSB_TRANSFER_TYPE_INTERRUPT: transfer_priv->request.TransferType = InterruptTransferType; break; - default: - usbi_err(ctx, "Wrong transfer type (%d) in usbdk_do_bulk_transfer", transfer->type); - return LIBUSB_ERROR_INVALID_PARAM; } if (IS_XFERIN(transfer)) @@ -599,10 +584,12 @@ static int usbdk_do_bulk_transfer(struct usbi_transfer *itransfer) case TransferSuccessAsync: break; case TransferFailure: - usbi_err(ctx, "ReadPipe/WritePipe failed: %s", windows_error_str(0)); + usbi_err(TRANSFER_CTX(transfer), "ReadPipe/WritePipe failed: %s", windows_error_str(0)); return LIBUSB_ERROR_IO; } + set_transfer_priv_handle(itransfer, priv->system_handle); + return LIBUSB_SUCCESS; } @@ -610,9 +597,8 @@ static int usbdk_do_iso_transfer(struct usbi_transfer *itransfer) { struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev); - struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer); - struct libusb_context *ctx = TRANSFER_CTX(transfer); - OVERLAPPED *overlapped = transfer_priv->pollable_fd.overlapped; + struct usbdk_transfer_priv *transfer_priv = get_usbdk_transfer_priv(itransfer); + OVERLAPPED *overlapped = get_transfer_priv_overlapped(itransfer); TransferResult transferRes; int i; @@ -624,14 +610,14 @@ static int usbdk_do_iso_transfer(struct usbi_transfer *itransfer) transfer_priv->IsochronousPacketsArray = malloc(transfer->num_iso_packets * sizeof(ULONG64)); transfer_priv->request.IsochronousPacketsArray = (PVOID64)transfer_priv->IsochronousPacketsArray; if (!transfer_priv->IsochronousPacketsArray) { - usbi_err(ctx, "Allocation of IsochronousPacketsArray failed"); + usbi_err(TRANSFER_CTX(transfer), "Allocation of IsochronousPacketsArray failed"); return LIBUSB_ERROR_NO_MEM; } transfer_priv->IsochronousResultsArray = malloc(transfer->num_iso_packets * sizeof(USB_DK_ISO_TRANSFER_RESULT)); transfer_priv->request.Result.IsochronousResultsArray = (PVOID64)transfer_priv->IsochronousResultsArray; if (!transfer_priv->IsochronousResultsArray) { - usbi_err(ctx, "Allocation of isochronousResultsArray failed"); + usbi_err(TRANSFER_CTX(transfer), "Allocation of isochronousResultsArray failed"); return LIBUSB_ERROR_NO_MEM; } @@ -653,39 +639,7 @@ static int usbdk_do_iso_transfer(struct usbi_transfer *itransfer) return LIBUSB_ERROR_IO; } - return LIBUSB_SUCCESS; -} - -static int usbdk_do_submit_transfer(struct usbi_transfer *itransfer, - short events, int (*transfer_fn)(struct usbi_transfer *)) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct libusb_context *ctx = TRANSFER_CTX(transfer); - struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev); - struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer); - struct winfd wfd; - int r; - - wfd = usbi_create_fd(); - if (wfd.fd < 0) - return LIBUSB_ERROR_NO_MEM; - - r = usbi_add_pollfd(ctx, wfd.fd, events); - if (r) { - usbi_close(wfd.fd); - return r; - } - - // Use transfer_priv to store data needed for async polling - transfer_priv->pollable_fd = wfd; - transfer_priv->system_handle = priv->system_handle; - - r = transfer_fn(itransfer); - if (r != LIBUSB_SUCCESS) { - usbi_remove_pollfd(ctx, wfd.fd); - usbdk_clear_transfer_priv(itransfer); - return r; - } + set_transfer_priv_handle(itransfer, priv->system_handle); return LIBUSB_SUCCESS; } @@ -693,129 +647,55 @@ static int usbdk_do_submit_transfer(struct usbi_transfer *itransfer, static int usbdk_submit_transfer(struct usbi_transfer *itransfer) { struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - int (*transfer_fn)(struct usbi_transfer *); - short events; switch (transfer->type) { case LIBUSB_TRANSFER_TYPE_CONTROL: - events = (transfer->buffer[0] & LIBUSB_ENDPOINT_IN) ? POLLIN : POLLOUT; - transfer_fn = usbdk_do_control_transfer; - break; + return usbdk_do_control_transfer(itransfer); 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; //TODO: Check whether we can support this in UsbDk - events = IS_XFERIN(transfer) ? POLLIN : POLLOUT; - transfer_fn = usbdk_do_bulk_transfer; - break; + return usbdk_do_bulk_transfer(itransfer); case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: - events = IS_XFERIN(transfer) ? POLLIN : POLLOUT; - transfer_fn = usbdk_do_iso_transfer; - break; + return usbdk_do_iso_transfer(itransfer); default: - usbi_err(TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type); - return LIBUSB_ERROR_INVALID_PARAM; + // Should not get here since windows_submit_transfer() validates + // the transfer->type field + usbi_err(TRANSFER_CTX(transfer), "unsupported endpoint type %d", transfer->type); + return LIBUSB_ERROR_NOT_SUPPORTED; } - - return usbdk_do_submit_transfer(itransfer, events, transfer_fn); } -static int usbdk_abort_transfers(struct usbi_transfer *itransfer) +static enum libusb_transfer_status usbdk_copy_transfer_data(struct usbi_transfer *itransfer, DWORD length) { struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct libusb_context *ctx = TRANSFER_CTX(transfer); - struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev); - struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer); - struct winfd *pollable_fd = &transfer_priv->pollable_fd; - - // Use CancelIoEx to cancel just a single transfer - if (CancelIoEx(priv->system_handle, pollable_fd->overlapped)) - return LIBUSB_SUCCESS; + struct usbdk_transfer_priv *transfer_priv = get_usbdk_transfer_priv(itransfer); - usbi_warn(ctx, "CancelIoEx failed: %s", windows_error_str(0)); - return LIBUSB_ERROR_NOT_FOUND; -} + UNUSED(length); -static int usbdk_cancel_transfer(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - - switch (transfer->type) { - case LIBUSB_TRANSFER_TYPE_CONTROL: - // Control transfers cancelled by IoCancelXXX() API - // No special treatment needed - return LIBUSB_SUCCESS; - case LIBUSB_TRANSFER_TYPE_BULK: - case LIBUSB_TRANSFER_TYPE_INTERRUPT: - case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: - return usbdk_abort_transfers(itransfer); - default: - usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type); - return LIBUSB_ERROR_INVALID_PARAM; - } -} - -static int usbdk_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size) -{ - itransfer->transferred += io_size; - return LIBUSB_TRANSFER_COMPLETED; -} - -static int usbdk_get_transfer_fd(struct usbi_transfer *itransfer) -{ - struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer); - return transfer_priv->pollable_fd.fd; -} - -static DWORD usbdk_translate_usbd_status(USBD_STATUS UsbdStatus) -{ - if (USBD_SUCCESS(UsbdStatus)) - return NO_ERROR; - - switch (UsbdStatus) { - case USBD_STATUS_TIMEOUT: - return ERROR_SEM_TIMEOUT; - case USBD_STATUS_CANCELED: - return ERROR_OPERATION_ABORTED; - default: - return ERROR_GEN_FAILURE; - } -} - -static void usbdk_get_overlapped_result(struct usbi_transfer *itransfer, DWORD *io_result, DWORD *io_size) -{ - struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer); - struct winfd *pollable_fd = &transfer_priv->pollable_fd; - - if (HasOverlappedIoCompletedSync(pollable_fd->overlapped) // Handle async requests that completed synchronously first - || GetOverlappedResult(transfer_priv->system_handle, pollable_fd->overlapped, io_size, FALSE)) { // Regular async overlapped - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - - if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) { - ULONG64 i; - for (i = 0; i < transfer_priv->request.IsochronousPacketsArraySize; i++) { - struct libusb_iso_packet_descriptor *lib_desc = &transfer->iso_packet_desc[i]; - - switch (transfer_priv->IsochronousResultsArray[i].TransferResult) { - case STATUS_SUCCESS: - case STATUS_CANCELLED: - case STATUS_REQUEST_CANCELED: - lib_desc->status = LIBUSB_TRANSFER_COMPLETED; // == ERROR_SUCCESS - break; - default: - lib_desc->status = LIBUSB_TRANSFER_ERROR; // ERROR_UNKNOWN_EXCEPTION; - break; - } - - lib_desc->actual_length = (unsigned int)transfer_priv->IsochronousResultsArray[i].ActualLength; + if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) { + ULONG64 i; + + for (i = 0; i < transfer_priv->request.IsochronousPacketsArraySize; i++) { + struct libusb_iso_packet_descriptor *lib_desc = &transfer->iso_packet_desc[i]; + + switch (transfer_priv->IsochronousResultsArray[i].TransferResult) { + case STATUS_SUCCESS: + case STATUS_CANCELLED: + case STATUS_REQUEST_CANCELED: + lib_desc->status = LIBUSB_TRANSFER_COMPLETED; // == ERROR_SUCCESS + break; + default: + lib_desc->status = LIBUSB_TRANSFER_ERROR; // ERROR_UNKNOWN_EXCEPTION; + break; } - } - *io_size = (DWORD)transfer_priv->request.Result.GenResult.BytesTransferred; - *io_result = usbdk_translate_usbd_status((USBD_STATUS)transfer_priv->request.Result.GenResult.UsbdStatus); - } else { - *io_result = GetLastError(); + lib_desc->actual_length = (unsigned int)transfer_priv->IsochronousResultsArray[i].ActualLength; + } } + + itransfer->transferred += (int)transfer_priv->request.Result.GenResult.BytesTransferred; + return usbd_status_to_libusb_transfer_status((USBD_STATUS)transfer_priv->request.Result.GenResult.UsbdStatus); } const struct windows_backend usbdk_backend = { @@ -837,9 +717,7 @@ const struct windows_backend usbdk_backend = { usbdk_reset_device, usbdk_destroy_device, usbdk_submit_transfer, - usbdk_cancel_transfer, + NULL, /* cancel_transfer */ usbdk_clear_transfer_priv, usbdk_copy_transfer_data, - usbdk_get_transfer_fd, - usbdk_get_overlapped_result, }; diff --git a/libusb/os/windows_winusb.c b/libusb/os/windows_winusb.c index 7cb17be..ce4d3a1 100644 --- a/libusb/os/windows_winusb.c +++ b/libusb/os/windows_winusb.c @@ -42,13 +42,7 @@ #define HANDLE_VALID(h) (((h) != NULL) && ((h) != INVALID_HANDLE_VALUE)) -// The 2 macros below are used in conjunction with safe loops. -#define LOOP_CHECK(fcall) \ - { \ - r = fcall; \ - if (r != LIBUSB_SUCCESS) \ - continue; \ - } +// The below macro is used in conjunction with safe loops. #define LOOP_BREAK(err) \ { \ r = err; \ @@ -56,7 +50,7 @@ } // WinUSB-like API prototypes -static int winusbx_init(struct libusb_context *ctx); +static bool winusbx_init(struct libusb_context *ctx); static void winusbx_exit(void); static int winusbx_open(int sub_api, struct libusb_device_handle *dev_handle); static void winusbx_close(int sub_api, struct libusb_device_handle *dev_handle); @@ -68,12 +62,11 @@ static int winusbx_set_interface_altsetting(int sub_api, struct libusb_device_ha static int winusbx_submit_iso_transfer(int sub_api, struct usbi_transfer *itransfer); static int winusbx_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer); static int winusbx_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint); -static int winusbx_abort_transfers(int sub_api, struct usbi_transfer *itransfer); -static int winusbx_abort_control(int sub_api, struct usbi_transfer *itransfer); +static int winusbx_cancel_transfer(int sub_api, struct usbi_transfer *itransfer); static int winusbx_reset_device(int sub_api, struct libusb_device_handle *dev_handle); -static int winusbx_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size); +static enum libusb_transfer_status winusbx_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, DWORD length); // HID API prototypes -static int hid_init(struct libusb_context *ctx); +static bool hid_init(struct libusb_context *ctx); static void hid_exit(void); static int hid_open(int sub_api, struct libusb_device_handle *dev_handle); static void hid_close(int sub_api, struct libusb_device_handle *dev_handle); @@ -83,9 +76,8 @@ static int hid_set_interface_altsetting(int sub_api, struct libusb_device_handle static int hid_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer); static int hid_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer); static int hid_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint); -static int hid_abort_transfers(int sub_api, struct usbi_transfer *itransfer); static int hid_reset_device(int sub_api, struct libusb_device_handle *dev_handle); -static int hid_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size); +static enum libusb_transfer_status hid_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, DWORD length); // Composite API prototypes static int composite_open(int sub_api, struct libusb_device_handle *dev_handle); static void composite_close(int sub_api, struct libusb_device_handle *dev_handle); @@ -96,28 +88,25 @@ static int composite_submit_control_transfer(int sub_api, struct usbi_transfer * static int composite_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer); static int composite_submit_iso_transfer(int sub_api, struct usbi_transfer *itransfer); static int composite_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint); -static int composite_abort_transfers(int sub_api, struct usbi_transfer *itransfer); -static int composite_abort_control(int sub_api, struct usbi_transfer *itransfer); +static int composite_cancel_transfer(int sub_api, struct usbi_transfer *itransfer); static int composite_reset_device(int sub_api, struct libusb_device_handle *dev_handle); -static int composite_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size); +static enum libusb_transfer_status composite_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, DWORD length); static usbi_mutex_t autoclaim_lock; // API globals -static HMODULE WinUSBX_handle = NULL; static struct winusb_interface WinUSBX[SUB_API_MAX]; #define CHECK_WINUSBX_AVAILABLE(sub_api) \ do { \ if (sub_api == SUB_API_NOTSET) \ sub_api = priv->sub_api; \ - if (!WinUSBX[sub_api].initialized) \ + if (WinUSBX[sub_api].hDll == NULL) \ return LIBUSB_ERROR_ACCESS; \ } while (0) -static bool api_hid_available = false; #define CHECK_HID_AVAILABLE \ do { \ - if (!api_hid_available) \ + if (DLL_HANDLE_NAME(hid) == NULL) \ return LIBUSB_ERROR_ACCESS; \ } while (0) @@ -183,40 +172,40 @@ static char *sanitize_path(const char *path) /* * Cfgmgr32, AdvAPI32, OLE32 and SetupAPI DLL functions */ -static BOOL init_dlls(void) +static bool init_dlls(void) { DLL_GET_HANDLE(Cfgmgr32); - DLL_LOAD_FUNC(Cfgmgr32, CM_Get_Parent, TRUE); - DLL_LOAD_FUNC(Cfgmgr32, CM_Get_Child, TRUE); + DLL_LOAD_FUNC(Cfgmgr32, CM_Get_Parent, true); + DLL_LOAD_FUNC(Cfgmgr32, CM_Get_Child, true); // Prefixed to avoid conflict with header files DLL_GET_HANDLE(AdvAPI32); - DLL_LOAD_FUNC_PREFIXED(AdvAPI32, p, RegQueryValueExW, TRUE); - DLL_LOAD_FUNC_PREFIXED(AdvAPI32, p, RegCloseKey, TRUE); + DLL_LOAD_FUNC_PREFIXED(AdvAPI32, p, RegQueryValueExW, true); + DLL_LOAD_FUNC_PREFIXED(AdvAPI32, p, RegCloseKey, true); DLL_GET_HANDLE(OLE32); - DLL_LOAD_FUNC_PREFIXED(OLE32, p, IIDFromString, TRUE); + DLL_LOAD_FUNC_PREFIXED(OLE32, p, IIDFromString, true); DLL_GET_HANDLE(SetupAPI); - DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetClassDevsA, TRUE); - DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiEnumDeviceInfo, TRUE); - DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiEnumDeviceInterfaces, TRUE); - DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetDeviceInstanceIdA, TRUE); - DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetDeviceInterfaceDetailA, TRUE); - DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetDeviceRegistryPropertyA, TRUE); - DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiDestroyDeviceInfoList, TRUE); - DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiOpenDevRegKey, TRUE); - DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiOpenDeviceInterfaceRegKey, TRUE); - - return TRUE; + DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetClassDevsA, true); + DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiEnumDeviceInfo, true); + DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiEnumDeviceInterfaces, true); + DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetDeviceInstanceIdA, true); + DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetDeviceInterfaceDetailA, true); + DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetDeviceRegistryPropertyA, true); + DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiDestroyDeviceInfoList, true); + DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiOpenDevRegKey, true); + DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiOpenDeviceInterfaceRegKey, true); + + return true; } static void exit_dlls(void) { - DLL_FREE_HANDLE(Cfgmgr32); - DLL_FREE_HANDLE(AdvAPI32); - DLL_FREE_HANDLE(OLE32); DLL_FREE_HANDLE(SetupAPI); + DLL_FREE_HANDLE(OLE32); + DLL_FREE_HANDLE(AdvAPI32); + DLL_FREE_HANDLE(Cfgmgr32); } /* @@ -391,13 +380,13 @@ static SP_DEVICE_INTERFACE_DETAIL_DATA_A *get_interface_details_filter(struct li goto err_exit; } } else { - usbi_err(ctx, "program assertion failed - http://msdn.microsoft.com/en-us/library/ms792901.aspx is wrong."); + usbi_err(ctx, "program assertion failed - http://msdn.microsoft.com/en-us/library/ms792901.aspx is wrong"); goto err_exit; } - dev_interface_details = calloc(1, size); + dev_interface_details = malloc(size); if (dev_interface_details == NULL) { - usbi_err(ctx, "could not allocate interface data for index %u.", _index); + usbi_err(ctx, "could not allocate interface data for index %u", _index); goto err_exit; } @@ -468,7 +457,8 @@ static int get_interface_by_endpoint(struct libusb_config_descriptor *conf_desc, { const struct libusb_interface *intf; const struct libusb_interface_descriptor *intf_desc; - int i, j, k; + uint8_t i, k; + int j; for (i = 0; i < conf_desc->bNumInterfaces; i++) { intf = &conf_desc->interface[i]; @@ -492,15 +482,14 @@ static int get_interface_by_endpoint(struct libusb_config_descriptor *conf_desc, */ static int windows_assign_endpoints(struct libusb_device_handle *dev_handle, int iface, int altsetting) { - int i, r; struct winusb_device_priv *priv = _device_priv(dev_handle->dev); struct libusb_config_descriptor *conf_desc; const struct libusb_interface_descriptor *if_desc; - struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); + int i, r; r = libusb_get_active_config_descriptor(dev_handle->dev, &conf_desc); if (r != LIBUSB_SUCCESS) { - usbi_warn(ctx, "could not read config descriptor: error %d", r); + usbi_warn(HANDLE_CTX(dev_handle), "could not read config descriptor: error %d", r); return r; } @@ -541,10 +530,10 @@ static int windows_assign_endpoints(struct libusb_device_handle *dev_handle, int // return -1 if not found, driver match number otherwise static int get_sub_api(char *driver, int api) { - int i; const char sep_str[2] = {LIST_SEPARATOR, 0}; char *tok, *tmp_str; size_t len = strlen(driver); + int i; if (len == 0) return SUB_API_NOTSET; @@ -573,7 +562,6 @@ static int get_sub_api(char *driver, int api) */ static int auto_claim(struct libusb_transfer *transfer, int *interface_number, int api_type) { - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); struct winusb_device_handle_priv *handle_priv = _device_handle_priv( transfer->dev_handle); struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev); @@ -596,13 +584,13 @@ static int auto_claim(struct libusb_transfer *transfer, int *interface_number, i && (libusb_claim_interface(transfer->dev_handle, current_interface) == LIBUSB_SUCCESS)) { usbi_dbg("auto-claimed interface %d for control request", current_interface); if (handle_priv->autoclaim_count[current_interface] != 0) - usbi_warn(ctx, "program assertion failed - autoclaim_count was nonzero"); + usbi_err(TRANSFER_CTX(transfer), "program assertion failed - autoclaim_count was nonzero"); handle_priv->autoclaim_count[current_interface]++; break; } } if (current_interface == USB_MAXINTERFACES) { - usbi_err(ctx, "could not auto-claim any interface"); + usbi_err(TRANSFER_CTX(transfer), "could not auto-claim any interface"); r = LIBUSB_ERROR_NOT_FOUND; } } else { @@ -619,7 +607,7 @@ static int auto_claim(struct libusb_transfer *transfer, int *interface_number, i static void auto_release(struct usbi_transfer *itransfer) { - struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); + struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer); struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); libusb_device_handle *dev_handle = transfer->dev_handle; struct winusb_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); @@ -647,9 +635,6 @@ static int winusb_init(struct libusb_context *ctx) { int i; - // We need a lock for proper auto-release - usbi_mutex_init(&autoclaim_lock); - // Load DLL imports if (!init_dlls()) { usbi_err(ctx, "could not resolve DLL functions"); @@ -658,11 +643,14 @@ static int winusb_init(struct libusb_context *ctx) // Initialize the low level APIs (we don't care about errors at this stage) for (i = 0; i < USB_API_MAX; i++) { - if (usb_api_backend[i].init && usb_api_backend[i].init(ctx)) + if (usb_api_backend[i].init && !usb_api_backend[i].init(ctx)) usbi_warn(ctx, "error initializing %s backend", usb_api_backend[i].designation); } + // We need a lock for proper auto-release + usbi_mutex_init(&autoclaim_lock); + return LIBUSB_SUCCESS; } @@ -675,13 +663,14 @@ static void winusb_exit(struct libusb_context *ctx) UNUSED(ctx); + usbi_mutex_destroy(&autoclaim_lock); + for (i = 0; i < USB_API_MAX; i++) { if (usb_api_backend[i].exit) usb_api_backend[i].exit(); } exit_dlls(); - usbi_mutex_destroy(&autoclaim_lock); } /* @@ -701,6 +690,8 @@ static void cache_config_descriptors(struct libusb_device *dev, HANDLE hub_handl if (dev->num_configurations == 0) return; + assert(sizeof(USB_DESCRIPTOR_REQUEST) == USB_DESCRIPTOR_REQUEST_SIZE); + priv->config_descriptor = calloc(dev->num_configurations, sizeof(PUSB_CONFIGURATION_DESCRIPTOR)); if (priv->config_descriptor == NULL) { usbi_err(ctx, "could not allocate configuration descriptor array for '%s'", priv->dev_id); @@ -714,7 +705,7 @@ static void cache_config_descriptors(struct libusb_device *dev, HANDLE hub_handl break; size = sizeof(cd_buf_short); - memset(&cd_buf_short, 0, size); + memset(&cd_buf_short.desc, 0, sizeof(cd_buf_short.desc)); cd_buf_short.req.ConnectionIndex = (ULONG)dev->port_number; cd_buf_short.req.SetupPacket.bmRequest = LIBUSB_ENDPOINT_IN; @@ -758,7 +749,7 @@ static void cache_config_descriptors(struct libusb_device *dev, HANDLE hub_handl continue; } - cd_data = (PUSB_CONFIGURATION_DESCRIPTOR)((UCHAR *)cd_buf_actual + sizeof(USB_DESCRIPTOR_REQUEST)); + cd_data = (PUSB_CONFIGURATION_DESCRIPTOR)((UCHAR *)cd_buf_actual + USB_DESCRIPTOR_REQUEST_SIZE); if ((size != ret_size) || (cd_data->wTotalLength != cd_buf_short.desc.wTotalLength)) { usbi_err(ctx, "unexpected configuration descriptor %u size (actual) for '%s'", i, priv->dev_id); @@ -774,12 +765,8 @@ static void cache_config_descriptors(struct libusb_device *dev, HANDLE hub_handl i, cd_data->bConfigurationValue, cd_data->wTotalLength); // Cache the descriptor - priv->config_descriptor[i] = malloc(cd_data->wTotalLength); - if (priv->config_descriptor[i] != NULL) { - memcpy(priv->config_descriptor[i], cd_data, cd_data->wTotalLength); - } else { - usbi_err(ctx, "could not allocate configuration descriptor %u buffer for '%s'", i, priv->dev_id); - } + priv->config_descriptor[i] = cd_data; + cd_buf_actual = NULL; } } @@ -853,7 +840,6 @@ static int init_device(struct libusb_device *dev, struct libusb_device *parent_d return LIBUSB_ERROR_ACCESS; } - memset(&conn_info, 0, sizeof(conn_info)); conn_info.ConnectionIndex = (ULONG)port_number; // coverity[tainted_data_argument] ginfotimeout = 20; @@ -873,31 +859,28 @@ static int init_device(struct libusb_device *dev, struct libusb_device *parent_d } memcpy(&priv->dev_descriptor, &(conn_info.DeviceDescriptor), sizeof(USB_DEVICE_DESCRIPTOR)); - dev->num_configurations = priv->dev_descriptor.bNumConfigurations; + dev->num_configurations = conn_info.DeviceDescriptor.bNumConfigurations; priv->active_config = conn_info.CurrentConfigurationValue; if (priv->active_config == 0) { - usbi_dbg("0x%x:0x%x found %u configurations (active conf: %u) \n", + usbi_dbg("0x%x:0x%x found %u configurations (not configured)", priv->dev_descriptor.idVendor, priv->dev_descriptor.idProduct, - dev->num_configurations, - priv->active_config); + dev->num_configurations); + SleepEx(50, TRUE); } - if (priv->active_config == 0) - Sleep(50); } while (priv->active_config == 0 && --ginfotimeout >= 0); if (priv->active_config == 0) { - usbi_dbg("after try 0x%x:0x%x found %u configurations (active conf: %u) \n", + usbi_info(ctx, "0x%x:0x%x found %u configurations but device isn't configured, " + "forcing current configuration to 1", priv->dev_descriptor.idVendor, priv->dev_descriptor.idProduct, - dev->num_configurations, - priv->active_config); - usbi_dbg("Force this device active config to 1 in libusb! \nNOTICE: Should not reach this place!!!!!! \n"); + dev->num_configurations); priv->active_config = 1; + } else { + usbi_dbg("found %u configurations (current config: %u)", dev->num_configurations, priv->active_config); } - usbi_dbg("found %u configurations (active conf: %u)", dev->num_configurations, priv->active_config); - // Cache as many config descriptors as we can cache_config_descriptors(dev, hub_handle); @@ -964,7 +947,7 @@ static int enumerate_hcd_root_hub(struct libusb_context *ctx, const char *dev_id session_id = (unsigned long)child_devinst; dev = usbi_get_device_by_session_id(ctx, session_id); if (dev == NULL) { - usbi_warn(ctx, "program assertion failed - HCD '%s' child not found", dev_id); + usbi_err(ctx, "program assertion failed - HCD '%s' child not found", dev_id); return LIBUSB_SUCCESS; } @@ -1093,20 +1076,20 @@ static int set_composite_interface(struct libusb_context *ctx, struct libusb_dev static int set_hid_interface(struct libusb_context *ctx, struct libusb_device *dev, char *dev_interface_path) { - int i; struct winusb_device_priv *priv = _device_priv(dev); + uint8_t i; if (priv->hid == NULL) { - usbi_err(ctx, "program assertion failed: parent is not HID"); + usbi_err(ctx, "program assertion failed - parent is not HID"); return LIBUSB_ERROR_NO_DEVICE; } else if (priv->hid->nb_interfaces == USB_MAXINTERFACES) { - usbi_err(ctx, "program assertion failed: max USB interfaces reached for HID device"); + usbi_err(ctx, "program assertion failed - max USB interfaces reached for HID device"); return LIBUSB_ERROR_NO_DEVICE; } for (i = 0; i < priv->hid->nb_interfaces; i++) { if ((priv->usb_interface[i].path != NULL) && strcmp(priv->usb_interface[i].path, dev_interface_path) == 0) { - usbi_dbg("interface[%d] already set to %s", i, dev_interface_path); + usbi_dbg("interface[%u] already set to %s", i, dev_interface_path); return LIBUSB_ERROR_ACCESS; } } @@ -1182,7 +1165,7 @@ static int winusb_get_device_list(struct libusb_context *ctx, struct discovered_ guid_list[DEV_PASS] = &GUID_DEVINTERFACE_USB_DEVICE; guid_list[HCD_PASS] = &GUID_DEVINTERFACE_USB_HOST_CONTROLLER; guid_list[GEN_PASS] = NULL; - if (api_hid_available) { + if (HidD_GetHidGuid != NULL) { HidD_GetHidGuid(&hid_guid); guid_list[HID_PASS] = &hid_guid; } else { @@ -1228,7 +1211,7 @@ static int winusb_get_device_list(struct libusb_context *ctx, struct discovered_ break; if ((pass == HCD_PASS) && (i == UINT8_MAX)) { - usbi_warn(ctx, "program assertion failed - found more than %u buses, skipping the rest.", UINT8_MAX); + usbi_warn(ctx, "program assertion failed - found more than %u buses, skipping the rest", UINT8_MAX); break; } @@ -1741,14 +1724,11 @@ static void winusb_destroy_device(struct libusb_device *dev) static void winusb_clear_transfer_priv(struct usbi_transfer *itransfer) { - struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); + struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer); struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev); int sub_api = priv->sub_api; - usbi_close(transfer_priv->pollable_fd.fd); - transfer_priv->pollable_fd = INVALID_WINFD; - transfer_priv->handle = NULL; safe_free(transfer_priv->hid_buffer); if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS && sub_api == SUB_API_WINUSB) { @@ -1756,7 +1736,7 @@ static void winusb_clear_transfer_priv(struct usbi_transfer *itransfer) if (WinUSBX[sub_api].UnregisterIsochBuffer(transfer_priv->isoch_buffer_handle)) { transfer_priv->isoch_buffer_handle = NULL; } else { - usbi_dbg("Couldn't unregister isoch buffer!"); + usbi_warn(TRANSFER_CTX(transfer), "failed to unregister WinUSB isoch buffer: %s", windows_error_str(0)); } } } @@ -1767,64 +1747,28 @@ static void winusb_clear_transfer_priv(struct usbi_transfer *itransfer) auto_release(itransfer); } -static int do_submit_transfer(struct usbi_transfer *itransfer, short events, - int (*transfer_fn)(int, struct usbi_transfer *)) -{ - struct libusb_context *ctx = ITRANSFER_CTX(itransfer); - struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - struct winfd wfd; - int r; - - wfd = usbi_create_fd(); - if (wfd.fd < 0) - return LIBUSB_ERROR_NO_MEM; - - r = usbi_add_pollfd(ctx, wfd.fd, events); - if (r) { - usbi_close(wfd.fd); - return r; - } - - // Use transfer_priv to store data needed for async polling - transfer_priv->pollable_fd = wfd; - - r = transfer_fn(SUB_API_NOTSET, itransfer); - - if ((r != LIBUSB_SUCCESS) && (r != LIBUSB_ERROR_OVERFLOW)) { - usbi_remove_pollfd(ctx, wfd.fd); - usbi_close(wfd.fd); - transfer_priv->pollable_fd = INVALID_WINFD; - } - - return r; -} - static int winusb_submit_transfer(struct usbi_transfer *itransfer) { struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); struct winusb_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: - 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; - events = IS_XFERIN(transfer) ? POLLIN : POLLOUT; transfer_fn = priv->apib->submit_bulk_transfer; break; case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: - 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: + // Should not get here since windows_submit_transfer() validates + // the transfer->type field usbi_err(TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type); return LIBUSB_ERROR_INVALID_PARAM; } @@ -1836,76 +1780,30 @@ static int winusb_submit_transfer(struct usbi_transfer *itransfer) return LIBUSB_ERROR_NOT_SUPPORTED; } - return do_submit_transfer(itransfer, events, transfer_fn); + return transfer_fn(SUB_API_NOTSET, itransfer); } -static int windows_abort_control(struct usbi_transfer *itransfer) +static int winusb_cancel_transfer(struct usbi_transfer *itransfer) { struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev); - CHECK_SUPPORTED_API(priv->apib, abort_control); + CHECK_SUPPORTED_API(priv->apib, cancel_transfer); - return priv->apib->abort_control(SUB_API_NOTSET, itransfer); + return priv->apib->cancel_transfer(SUB_API_NOTSET, itransfer); } -static int windows_abort_transfers(struct usbi_transfer *itransfer) +static enum libusb_transfer_status winusb_copy_transfer_data(struct usbi_transfer *itransfer, DWORD length) { struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev); - CHECK_SUPPORTED_API(priv->apib, abort_transfers); - - return priv->apib->abort_transfers(SUB_API_NOTSET, itransfer); -} - -static int winusb_cancel_transfer(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - - switch (transfer->type) { - case LIBUSB_TRANSFER_TYPE_CONTROL: - return windows_abort_control(itransfer); - case LIBUSB_TRANSFER_TYPE_BULK: - case LIBUSB_TRANSFER_TYPE_INTERRUPT: - case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: - return windows_abort_transfers(itransfer); - case LIBUSB_TRANSFER_TYPE_BULK_STREAM: - return LIBUSB_ERROR_NOT_SUPPORTED; - default: - usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type); - return LIBUSB_ERROR_INVALID_PARAM; + if (priv->apib->copy_transfer_data == NULL) { + usbi_err(TRANSFER_CTX(transfer), "program assertion failed - no function to copy transfer data"); + return LIBUSB_TRANSFER_ERROR; } -} -static int winusb_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev); - return priv->apib->copy_transfer_data(SUB_API_NOTSET, itransfer, io_size); -} - -static int winusb_get_transfer_fd(struct usbi_transfer *itransfer) -{ - struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - return transfer_priv->pollable_fd.fd; -} - -static void winusb_get_overlapped_result(struct usbi_transfer *itransfer, - DWORD *io_result, DWORD *io_size) -{ - struct winusb_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(transfer_priv->handle, pollable_fd->overlapped, io_size, FALSE)) { - // Regular async overlapped - *io_result = NO_ERROR; - } else { - *io_result = GetLastError(); - } + return priv->apib->copy_transfer_data(SUB_API_NOTSET, itransfer, length); } // NB: MSVC6 does not support named initializers. @@ -1931,8 +1829,6 @@ const struct windows_backend winusb_backend = { winusb_cancel_transfer, winusb_clear_transfer_priv, winusb_copy_transfer_data, - winusb_get_transfer_fd, - winusb_get_overlapped_result, }; /* @@ -1971,8 +1867,7 @@ const struct windows_usb_api_backend usb_api_backend[USB_API_MAX] = { composite_submit_bulk_transfer, composite_submit_iso_transfer, composite_submit_control_transfer, - composite_abort_control, - composite_abort_transfers, + composite_cancel_transfer, composite_copy_transfer_data, }, { @@ -1993,8 +1888,7 @@ const struct windows_usb_api_backend usb_api_backend[USB_API_MAX] = { winusbx_submit_bulk_transfer, winusbx_submit_iso_transfer, winusbx_submit_control_transfer, - winusbx_abort_control, - winusbx_abort_transfers, + winusbx_cancel_transfer, winusbx_copy_transfer_data, }, { @@ -2015,8 +1909,7 @@ const struct windows_usb_api_backend usb_api_backend[USB_API_MAX] = { hid_submit_bulk_transfer, NULL, /* submit_iso_transfer */ hid_submit_control_transfer, - hid_abort_transfers, - hid_abort_transfers, + NULL, /* cancel_transfer */ hid_copy_transfer_data, }, }; @@ -2025,105 +1918,159 @@ const struct windows_usb_api_backend usb_api_backend[USB_API_MAX] = { /* * WinUSB-like (WinUSB, libusb0/libusbK through libusbk DLL) API functions */ -#define WinUSBX_Set(fn) \ +#define WinUSB_Set(h, fn, required) \ do { \ - if (native_winusb) \ - WinUSBX[i].fn = (WinUsb_##fn##_t)GetProcAddress(h, "WinUsb_" #fn); \ - else \ - pLibK_GetProcAddress((PVOID *)&WinUSBX[i].fn, i, KUSB_FNID_##fn); \ + WinUSBX[SUB_API_WINUSB].fn = (WinUsb_##fn##_t)GetProcAddress(h, "WinUsb_" #fn); \ + if (required && (WinUSBX[SUB_API_WINUSB].fn == NULL)) { \ + usbi_err(ctx, "GetProcAddress() failed for WinUsb_%s", #fn); \ + goto cleanup_winusb; \ + } \ } while (0) -#define NativeWinUSBOnly_Set(fn) \ +#define libusbK_Set(sub_api, fn, required) \ do { \ - if (native_winusb) \ - WinUSBX[i].fn = (WinUsb_##fn##_t)GetProcAddress(h, "WinUsb_" #fn); \ - else \ - WinUSBX[i].fn = NULL; \ + pLibK_GetProcAddress((PVOID *)&WinUSBX[sub_api].fn, sub_api, KUSB_FNID_##fn); \ + if (required && (WinUSBX[sub_api].fn == NULL)) { \ + usbi_err(ctx, "LibK_GetProcAddress() failed for LibK_%s", #fn); \ + goto cleanup_libusbk; \ + } \ } while (0) -static int winusbx_init(struct libusb_context *ctx) +static bool winusbx_init(struct libusb_context *ctx) { - HMODULE h; - bool native_winusb; - int i; - KLIB_VERSION LibK_Version; - LibK_GetProcAddress_t pLibK_GetProcAddress = NULL; - LibK_GetVersion_t pLibK_GetVersion; + HMODULE hWinUSB, hlibusbK; + + hWinUSB = LoadLibraryA("WinUSB"); + if (hWinUSB != NULL) { + WinUSB_Set(hWinUSB, AbortPipe, true); + WinUSB_Set(hWinUSB, ControlTransfer, true); + WinUSB_Set(hWinUSB, FlushPipe, true); + WinUSB_Set(hWinUSB, Free, true); + WinUSB_Set(hWinUSB, GetAssociatedInterface, true); + WinUSB_Set(hWinUSB, Initialize, true); + WinUSB_Set(hWinUSB, ReadPipe, true); + WinUSB_Set(hWinUSB, ResetPipe, true); + WinUSB_Set(hWinUSB, SetCurrentAlternateSetting, true); + WinUSB_Set(hWinUSB, SetPipePolicy, true); + WinUSB_Set(hWinUSB, WritePipe, true); + + // Check for isochronous transfers support (available starting with Windows 8.1) + WinUSB_Set(hWinUSB, ReadIsochPipeAsap, false); + if (WinUSBX[SUB_API_WINUSB].ReadIsochPipeAsap != NULL) { + WinUSB_Set(hWinUSB, QueryPipeEx, true); + WinUSB_Set(hWinUSB, RegisterIsochBuffer, true); + WinUSB_Set(hWinUSB, UnregisterIsochBuffer, true); + WinUSB_Set(hWinUSB, WriteIsochPipeAsap, true); + } - h = LoadLibraryA("libusbK"); + WinUSBX[SUB_API_WINUSB].hDll = hWinUSB; - if (h == NULL) { - usbi_info(ctx, "libusbK DLL is not available, will use native WinUSB"); - h = LoadLibraryA("WinUSB"); + usbi_info(ctx, "WinUSB DLL available (%s isoch support)", + (WinUSBX[SUB_API_WINUSB].ReadIsochPipeAsap != NULL) ? "with" : "without"); - if (h == NULL) { - usbi_warn(ctx, "WinUSB DLL is not available either, " - "you will not be able to access devices outside of enumeration"); - return LIBUSB_ERROR_NOT_FOUND; +cleanup_winusb: + if (WinUSBX[SUB_API_WINUSB].hDll == NULL) { + usbi_err(ctx, "failed to initialize WinUSB"); + memset(&WinUSBX[SUB_API_WINUSB], 0, sizeof(WinUSBX[SUB_API_WINUSB])); + FreeLibrary(hWinUSB); + hWinUSB = NULL; } } else { - usbi_dbg("using libusbK DLL for universal access"); - pLibK_GetVersion = (LibK_GetVersion_t)GetProcAddress(h, "LibK_GetVersion"); + usbi_info(ctx, "WinUSB DLL is not available"); + } + + hlibusbK = LoadLibraryA("libusbK"); + if (hlibusbK != NULL) { + LibK_GetVersion_t pLibK_GetVersion; + LibK_GetProcAddress_t pLibK_GetProcAddress; + int sub_api = 0; + + pLibK_GetVersion = (LibK_GetVersion_t)GetProcAddress(hlibusbK, "LibK_GetVersion"); if (pLibK_GetVersion != NULL) { + KLIB_VERSION LibK_Version; + pLibK_GetVersion(&LibK_Version); - usbi_dbg("libusbK version: %d.%d.%d.%d", LibK_Version.Major, LibK_Version.Minor, + usbi_dbg("libusbK DLL found, version: %d.%d.%d.%d", LibK_Version.Major, LibK_Version.Minor, LibK_Version.Micro, LibK_Version.Nano); + } else { + usbi_dbg("libusbK DLL found, version unknown"); } - pLibK_GetProcAddress = (LibK_GetProcAddress_t)GetProcAddress(h, "LibK_GetProcAddress"); + + pLibK_GetProcAddress = (LibK_GetProcAddress_t)GetProcAddress(hlibusbK, "LibK_GetProcAddress"); if (pLibK_GetProcAddress == NULL) { usbi_err(ctx, "LibK_GetProcAddress() not found in libusbK DLL"); - FreeLibrary(h); - return LIBUSB_ERROR_NOT_FOUND; + goto cleanup_libusbk; } - } - native_winusb = (pLibK_GetProcAddress == NULL); - for (i = 0; i < SUB_API_MAX; i++) { - WinUSBX_Set(AbortPipe); - WinUSBX_Set(ControlTransfer); - WinUSBX_Set(FlushPipe); - WinUSBX_Set(Free); - WinUSBX_Set(GetAssociatedInterface); - WinUSBX_Set(Initialize); - WinUSBX_Set(ReadPipe); - if (!native_winusb) - WinUSBX_Set(ResetDevice); - WinUSBX_Set(ResetPipe); - WinUSBX_Set(SetCurrentAlternateSetting); - WinUSBX_Set(SetPipePolicy); - WinUSBX_Set(WritePipe); - WinUSBX_Set(IsoReadPipe); - WinUSBX_Set(IsoWritePipe); - NativeWinUSBOnly_Set(RegisterIsochBuffer); - NativeWinUSBOnly_Set(UnregisterIsochBuffer); - NativeWinUSBOnly_Set(WriteIsochPipeAsap); - NativeWinUSBOnly_Set(ReadIsochPipeAsap); - NativeWinUSBOnly_Set(QueryPipeEx); - - if (WinUSBX[i].Initialize != NULL) { - WinUSBX[i].initialized = true; - // Assume driver supports CancelIoEx() - WinUSBX[i].CancelIoEx_supported = true; - usbi_dbg("initalized sub API %s", winusbx_driver_names[i]); - } else { - usbi_warn(ctx, "Failed to initalize sub API %s", winusbx_driver_names[i]); - WinUSBX[i].initialized = false; + // NB: The below for loop works because the sub_api value for WinUSB + // is a higher value than that of libusbK and libusb0 + for (; sub_api < SUB_API_WINUSB; sub_api++) { + libusbK_Set(sub_api, AbortPipe, true); + libusbK_Set(sub_api, ControlTransfer, true); + libusbK_Set(sub_api, FlushPipe, true); + libusbK_Set(sub_api, Free, true); + libusbK_Set(sub_api, GetAssociatedInterface, true); + libusbK_Set(sub_api, Initialize, true); + libusbK_Set(sub_api, ReadPipe, true); + libusbK_Set(sub_api, ResetPipe, true); + libusbK_Set(sub_api, SetCurrentAlternateSetting, true); + libusbK_Set(sub_api, SetPipePolicy, true); + libusbK_Set(sub_api, WritePipe, true); + + // Optional isochronous support + libusbK_Set(sub_api, IsoReadPipe, false); + if (WinUSBX[sub_api].IsoReadPipe != NULL) + libusbK_Set(sub_api, IsoWritePipe, true); + + // Optional device reset support + libusbK_Set(sub_api, ResetDevice, false); + + WinUSBX[sub_api].hDll = hlibusbK; + } + +cleanup_libusbk: + if (sub_api < SUB_API_WINUSB) { + usbi_err(ctx, "failed to initialize libusbK"); + while (sub_api >= 0) { + memset(&WinUSBX[sub_api], 0, sizeof(WinUSBX[sub_api])); + sub_api--; + } + FreeLibrary(hlibusbK); + hlibusbK = NULL; } + } else { + usbi_info(ctx, "libusbK DLL is not available"); } - WinUSBX_handle = h; - return LIBUSB_SUCCESS; + if ((hWinUSB == NULL) && (hlibusbK == NULL)) { + usbi_warn(ctx, "neither WinUSB nor libusbK DLLs were found, " + "you will not be able to access devices outside of enumeration"); + return false; + } + + return true; } static void winusbx_exit(void) { - if (WinUSBX_handle != NULL) { - FreeLibrary(WinUSBX_handle); - WinUSBX_handle = NULL; + bool loaded = false; + HMODULE hDll; - /* Reset the WinUSBX API structures */ - memset(&WinUSBX, 0, sizeof(WinUSBX)); + hDll = WinUSBX[SUB_API_LIBUSBK].hDll; + if (hDll != NULL) { + FreeLibrary(hDll); + loaded = true; + } + + hDll = WinUSBX[SUB_API_WINUSB].hDll; + if (hDll != NULL) { + FreeLibrary(hDll); + loaded = true; } + + // Reset the WinUSBX API structures if something was loaded + if (loaded) + memset(&WinUSBX, 0, sizeof(WinUSBX)); } // NB: open and close must ensure that they only handle interface of @@ -2131,7 +2078,6 @@ static void winusbx_exit(void) // composite_open(), with interfaces belonging to different APIs static int winusbx_open(int sub_api, struct libusb_device_handle *dev_handle) { - struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); struct winusb_device_priv *priv = _device_priv(dev_handle->dev); struct winusb_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); HANDLE file_handle; @@ -2144,9 +2090,9 @@ static int winusbx_open(int sub_api, struct libusb_device_handle *dev_handle) if ((priv->usb_interface[i].path != NULL) && (priv->usb_interface[i].apib->id == USB_API_WINUSBX)) { file_handle = CreateFileA(priv->usb_interface[i].path, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, - NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); + NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); if (file_handle == INVALID_HANDLE_VALUE) { - usbi_err(ctx, "could not open device %s (interface %d): %s", priv->usb_interface[i].path, i, windows_error_str(0)); + usbi_err(HANDLE_CTX(dev_handle), "could not open device %s (interface %d): %s", priv->usb_interface[i].path, i, windows_error_str(0)); switch (GetLastError()) { case ERROR_FILE_NOT_FOUND: // The device was disconnected return LIBUSB_ERROR_NO_DEVICE; @@ -2173,7 +2119,7 @@ static void winusbx_close(int sub_api, struct libusb_device_handle *dev_handle) if (sub_api == SUB_API_NOTSET) sub_api = priv->sub_api; - if (!WinUSBX[sub_api].initialized) + if (WinUSBX[sub_api].hDll == NULL) return; if (priv->apib->id == USB_API_COMPOSITE) { @@ -2220,7 +2166,7 @@ static int winusbx_configure_endpoints(int sub_api, struct libusb_device_handle CHECK_WINUSBX_AVAILABLE(sub_api); - // With handle and enpoints set (in parent), we can setup the default pipe properties + // With handle and endpoints set (in parent), we can setup the default pipe properties // see http://download.microsoft.com/download/D/1/D/D1DD7745-426B-4CC3-A269-ABBBE427C0EF/DVC-T705_DDC08.pptx for (i = -1; i < priv->usb_interface[iface].nb_endpoints; i++) { endpoint_address = (i == -1) ? 0 : priv->usb_interface[iface].endpoint[i]; @@ -2263,7 +2209,7 @@ static int winusbx_configure_endpoints(int sub_api, struct libusb_device_handle static int winusbx_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface) { - struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); + struct libusb_context *ctx = HANDLE_CTX(dev_handle); struct winusb_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); struct winusb_device_priv *priv = _device_priv(dev_handle->dev); bool is_using_usbccgp = (priv->apib->id == USB_API_COMPOSITE); @@ -2313,7 +2259,7 @@ static int winusbx_claim_interface(int sub_api, struct libusb_device_handle *dev if (strncmp(dev_path_no_guid, priv->usb_interface[iface].path, strlen(dev_path_no_guid)) == 0) { file_handle = CreateFileA(filter_path, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, - NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); + NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); if (file_handle != INVALID_HANDLE_VALUE) { if (WinUSBX[sub_api].Initialize(file_handle, &winusb_handle)) { // Replace the existing file handle with the working one @@ -2467,12 +2413,11 @@ static int interface_by_endpoint(struct winusb_device_priv *priv, static int winusbx_submit_control_transfer(int sub_api, 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 winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev); - struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); + struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer); struct winusb_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); PWINUSB_SETUP_PACKET setup = (PWINUSB_SETUP_PACKET)transfer->buffer; - ULONG size, transferred; + ULONG size; HANDLE winusb_handle; OVERLAPPED *overlapped; int current_interface; @@ -2497,26 +2442,25 @@ static int winusbx_submit_control_transfer(int sub_api, struct usbi_transfer *it usbi_dbg("will use interface %d", current_interface); - transfer_priv->handle = winusb_handle = handle_priv->interface_handle[current_interface].api_handle; - overlapped = transfer_priv->pollable_fd.overlapped; + winusb_handle = handle_priv->interface_handle[current_interface].api_handle; + set_transfer_priv_handle(itransfer, handle_priv->interface_handle[current_interface].dev_handle); + overlapped = get_transfer_priv_overlapped(itransfer); // Sending of set configuration control requests from WinUSB creates issues, except when using libusb0.sys if (sub_api != SUB_API_LIBUSB0 && (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_warn(TRANSFER_CTX(transfer), "cannot set configuration other than the default one"); return LIBUSB_ERROR_INVALID_PARAM; } windows_force_sync_completion(overlapped, 0); } else { - if (!WinUSBX[sub_api].ControlTransfer(winusb_handle, *setup, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, size, &transferred, 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_warn(TRANSFER_CTX(transfer), "ControlTransfer failed: %s", windows_error_str(0)); return LIBUSB_ERROR_IO; } - } else { - windows_force_sync_completion(overlapped, transferred); } } @@ -2527,7 +2471,6 @@ static int winusbx_submit_control_transfer(int sub_api, struct usbi_transfer *it static int winusbx_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting) { - struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); struct winusb_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); struct winusb_device_priv *priv = _device_priv(dev_handle->dev); HANDLE winusb_handle; @@ -2539,37 +2482,18 @@ static int winusbx_set_interface_altsetting(int sub_api, struct libusb_device_ha winusb_handle = handle_priv->interface_handle[iface].api_handle; if (!HANDLE_VALID(winusb_handle)) { - usbi_err(ctx, "interface must be claimed first"); + usbi_err(HANDLE_CTX(dev_handle), "interface must be claimed first"); return LIBUSB_ERROR_NOT_FOUND; } if (!WinUSBX[sub_api].SetCurrentAlternateSetting(winusb_handle, (UCHAR)altsetting)) { - usbi_err(ctx, "SetCurrentAlternateSetting failed: %s", windows_error_str(0)); + usbi_err(HANDLE_CTX(dev_handle), "SetCurrentAlternateSetting failed: %s", windows_error_str(0)); return LIBUSB_ERROR_IO; } return LIBUSB_SUCCESS; } -static enum libusb_transfer_status usbd_status_to_libusb_transfer_status(USBD_STATUS status) -{ - if (USBD_SUCCESS(status)) - return LIBUSB_TRANSFER_COMPLETED; - - switch (status) { - case USBD_STATUS_TIMEOUT: - return LIBUSB_TRANSFER_TIMED_OUT; - case USBD_STATUS_CANCELED: - return LIBUSB_TRANSFER_CANCELLED; - case USBD_STATUS_ENDPOINT_HALTED: - return LIBUSB_TRANSFER_STALL; - case USBD_STATUS_DEVICE_GONE: - return LIBUSB_TRANSFER_NO_DEVICE; - default: - usbi_dbg("USBD_STATUS 0x%08lx translated to LIBUSB_TRANSFER_ERROR", ULONG_CAST(status)); - return LIBUSB_TRANSFER_ERROR; - } -} static void WINAPI winusbx_native_iso_transfer_continue_stream_callback(struct libusb_transfer *transfer) { @@ -2578,27 +2502,24 @@ static void WINAPI winusbx_native_iso_transfer_continue_stream_callback(struct l // The role of this callback is to fallback to ContinueStream = FALSE if the transfer // did not succeed. - struct winusb_transfer_priv *transfer_priv = (struct winusb_transfer_priv *) - usbi_transfer_get_os_priv(LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer)); - BOOL fallback = (transfer->status != LIBUSB_TRANSFER_COMPLETED); + struct winusb_transfer_priv *transfer_priv = + get_winusb_transfer_priv(LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer)); + bool fallback = (transfer->status != LIBUSB_TRANSFER_COMPLETED); int idx; // Restore the user callback transfer->callback = transfer_priv->iso_user_callback; - for (idx = 0; idx < transfer->num_iso_packets && !fallback; ++idx) { - if (transfer->iso_packet_desc[idx].status != LIBUSB_TRANSFER_COMPLETED) { - fallback = TRUE; - } + for (idx = 0; idx < transfer->num_iso_packets && !fallback; idx++) { + if (transfer->iso_packet_desc[idx].status != LIBUSB_TRANSFER_COMPLETED) + fallback = true; } if (!fallback) { // If the transfer was successful, we restore the user callback and call it. - if (transfer->callback) { + if (transfer->callback) transfer->callback(transfer); - } - } - else { + } else { // If the transfer wasn't successful we reschedule the transfer while forcing it // not to continue the stream. This might results in a 5-ms delay. transfer_priv->iso_break_stream = TRUE; @@ -2608,27 +2529,27 @@ static void WINAPI winusbx_native_iso_transfer_continue_stream_callback(struct l static int winusbx_submit_iso_transfer(int sub_api, 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 winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); + struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer); struct winusb_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev); HANDLE winusb_handle; OVERLAPPED *overlapped; - bool ret; + BOOL ret; int current_interface; CHECK_WINUSBX_AVAILABLE(sub_api); 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"); + usbi_err(TRANSFER_CTX(transfer), "unable to match endpoint to an open interface - cancelling transfer"); return LIBUSB_ERROR_NOT_FOUND; - } else { - usbi_dbg("matched endpoint %02X with interface %d", transfer->endpoint, current_interface); } - transfer_priv->handle = winusb_handle = handle_priv->interface_handle[current_interface].api_handle; - overlapped = transfer_priv->pollable_fd.overlapped; + usbi_dbg("matched endpoint %02X with interface %d", transfer->endpoint, current_interface); + + winusb_handle = handle_priv->interface_handle[current_interface].api_handle; + set_transfer_priv_handle(itransfer, handle_priv->interface_handle[current_interface].dev_handle); + overlapped = get_transfer_priv_overlapped(itransfer); if ((sub_api == SUB_API_LIBUSBK) || (sub_api == SUB_API_LIBUSB0)) { int i; @@ -2636,6 +2557,11 @@ static int winusbx_submit_iso_transfer(int sub_api, struct usbi_transfer *itrans size_t iso_ctx_size; PKISO_CONTEXT iso_context; + if (WinUSBX[sub_api].IsoReadPipe == NULL) { + usbi_warn(TRANSFER_CTX(transfer), "libusbK DLL does not support isoch transfers"); + return LIBUSB_ERROR_NOT_SUPPORTED; + } + iso_ctx_size = sizeof(KISO_CONTEXT) + (transfer->num_iso_packets * sizeof(KISO_PACKET)); transfer_priv->iso_context = iso_context = calloc(1, iso_ctx_size); if (transfer_priv->iso_context == NULL) @@ -2660,42 +2586,29 @@ static int winusbx_submit_iso_transfer(int sub_api, struct usbi_transfer *itrans ret = WinUSBX[sub_api].IsoWritePipe(winusb_handle, transfer->endpoint, transfer->buffer, transfer->length, overlapped, iso_context); } - if (!ret) { - if (GetLastError() != ERROR_IO_PENDING) { - usbi_err(ctx, "IsoReadPipe/IsoWritePipe failed: %s", windows_error_str(0)); - return LIBUSB_ERROR_IO; - } - } else { - windows_force_sync_completion(overlapped, (ULONG)transfer->length); + if (!ret && GetLastError() != ERROR_IO_PENDING) { + usbi_err(TRANSFER_CTX(transfer), "IsoReadPipe/IsoWritePipe failed: %s", windows_error_str(0)); + return LIBUSB_ERROR_IO; } transfer_priv->interface_number = (uint8_t)current_interface; return LIBUSB_SUCCESS; - } - else if (sub_api == SUB_API_WINUSB) { + } else if (sub_api == SUB_API_WINUSB) { WINUSB_PIPE_INFORMATION_EX pipe_info_ex = { 0 }; WINUSB_ISOCH_BUFFER_HANDLE buffer_handle; ULONG iso_transfer_size_multiple; int out_transfer_length = 0; int idx; -# define WINUSBX_CHECK_API_SUPPORTED(API) \ - if (WinUSBX[sub_api].API == NULL) \ - { \ - usbi_dbg(#API " isn't available"); \ - return LIBUSB_ERROR_NOT_SUPPORTED; \ - } - // Depending on the version of Microsoft WinUSB, isochronous transfers may not be supported. - WINUSBX_CHECK_API_SUPPORTED(RegisterIsochBuffer); - WINUSBX_CHECK_API_SUPPORTED(ReadIsochPipeAsap); - WINUSBX_CHECK_API_SUPPORTED(WriteIsochPipeAsap); - WINUSBX_CHECK_API_SUPPORTED(UnregisterIsochBuffer); - WINUSBX_CHECK_API_SUPPORTED(QueryPipeEx); + if (WinUSBX[sub_api].ReadIsochPipeAsap == NULL) { + usbi_warn(TRANSFER_CTX(transfer), "WinUSB DLL does not support isoch transfers"); + return LIBUSB_ERROR_NOT_SUPPORTED; + } if (sizeof(struct libusb_iso_packet_descriptor) != sizeof(USBD_ISO_PACKET_DESCRIPTOR)) { - usbi_dbg("The size of Microsoft WinUsb and libusb isochronous packet descriptor doesn't match."); + usbi_err(TRANSFER_CTX(transfer), "size of WinUsb and libusb isoch packet descriptors don't match"); return LIBUSB_ERROR_NOT_SUPPORTED; } @@ -2703,18 +2616,17 @@ static int winusbx_submit_iso_transfer(int sub_api, struct usbi_transfer *itrans for (idx = 0; idx < priv->usb_interface[current_interface].nb_endpoints; ++idx) { ret = WinUSBX[sub_api].QueryPipeEx(winusb_handle, (UINT8)priv->usb_interface[current_interface].current_altsetting, (UCHAR)idx, &pipe_info_ex); if (!ret) { - usbi_dbg("Couldn't query interface settings for USB pipe with index %d. Error: %s", idx, windows_error_str(0)); + usbi_err(TRANSFER_CTX(transfer), "couldn't query interface settings for USB pipe with index %d. Error: %s", idx, windows_error_str(0)); return LIBUSB_ERROR_NOT_FOUND; } - if (pipe_info_ex.PipeId == transfer->endpoint && pipe_info_ex.PipeType == UsbdPipeTypeIsochronous) { + if (pipe_info_ex.PipeId == transfer->endpoint && pipe_info_ex.PipeType == UsbdPipeTypeIsochronous) break; - } } // Make sure we found the index. - if (idx >= priv->usb_interface[current_interface].nb_endpoints) { - usbi_dbg("Couldn't find the isochronous endpoint %02x.", transfer->endpoint); + if (idx == priv->usb_interface[current_interface].nb_endpoints) { + usbi_err(TRANSFER_CTX(transfer), "couldn't find isoch endpoint 0x%02x", transfer->endpoint); return LIBUSB_ERROR_NOT_FOUND; } @@ -2722,27 +2634,25 @@ static int winusbx_submit_iso_transfer(int sub_api, struct usbi_transfer *itrans int interval = pipe_info_ex.Interval; // For high-speed and SuperSpeed device, the interval is 2**(bInterval-1). - if (libusb_get_device_speed(libusb_get_device(transfer->dev_handle)) >= LIBUSB_SPEED_HIGH) { + if (transfer->dev_handle->dev->speed >= LIBUSB_SPEED_HIGH) interval = (1 << (pipe_info_ex.Interval - 1)); - } - // WinUSB only supports isochronous transfers spanning a full USB frames. Later, we might be smarter about this + // WinUSB only supports isoch transfers spanning a full USB frames. Later, we might be smarter about this // and allocate a temporary buffer. However, this is harder than it seems as its destruction would depend on overlapped // IO... iso_transfer_size_multiple = (pipe_info_ex.MaximumBytesPerInterval * 8) / interval; if (transfer->length % iso_transfer_size_multiple != 0) { - usbi_dbg("The length of isochronous buffer must be a multiple of the MaximumBytesPerInterval * 8 / Interval"); + usbi_err(TRANSFER_CTX(transfer), "length of isoch buffer must be a multiple of the MaximumBytesPerInterval * 8 / Interval"); return LIBUSB_ERROR_INVALID_PARAM; } - } - else { - // If this is an OUT transfer, we make sure the isochronous packets are contiguous as this isn't supported otherwise. - BOOL size_should_be_zero = FALSE; - out_transfer_length = 0; + } else { + // If this is an OUT transfer, we make sure the isoch packets are contiguous as this isn't supported otherwise. + bool size_should_be_zero = false; + for (idx = 0; idx < transfer->num_iso_packets; ++idx) { if ((size_should_be_zero && transfer->iso_packet_desc[idx].length != 0) || (transfer->iso_packet_desc[idx].length != pipe_info_ex.MaximumBytesPerInterval && idx + 1 < transfer->num_iso_packets && transfer->iso_packet_desc[idx + 1].length > 0)) { - usbi_dbg("Isochronous packets for OUT transfer with Microsoft WinUSB must be contiguous in memory."); + usbi_err(TRANSFER_CTX(transfer), "isoch packets for OUT transfer with WinUSB must be contiguous in memory"); return LIBUSB_ERROR_INVALID_PARAM; } @@ -2755,15 +2665,15 @@ static int winusbx_submit_iso_transfer(int sub_api, struct usbi_transfer *itrans if (WinUSBX[sub_api].UnregisterIsochBuffer(transfer_priv->isoch_buffer_handle)) { transfer_priv->isoch_buffer_handle = NULL; } else { - usbi_dbg("Couldn't unregister the Microsoft WinUSB isochronous buffer: %s", windows_error_str(0)); + usbi_err(TRANSFER_CTX(transfer), "failed to unregister WinUSB isoch buffer: %s", windows_error_str(0)); return LIBUSB_ERROR_OTHER; } } - // Register the isochronous buffer to the operating system. + // Register the isoch buffer to the operating system. ret = WinUSBX[sub_api].RegisterIsochBuffer(winusb_handle, transfer->endpoint, transfer->buffer, transfer->length, &buffer_handle); if (!ret) { - usbi_dbg("Microsoft WinUSB refused to allocate an isochronous buffer."); + usbi_err(TRANSFER_CTX(transfer), "failed to register WinUSB isoch buffer: %s", windows_error_str(0)); return LIBUSB_ERROR_NO_MEM; } @@ -2780,36 +2690,22 @@ static int winusbx_submit_iso_transfer(int sub_api, struct usbi_transfer *itrans } // Initiate the transfers. - if (IS_XFERIN(transfer)) { + if (IS_XFERIN(transfer)) ret = WinUSBX[sub_api].ReadIsochPipeAsap(buffer_handle, 0, transfer->length, !transfer_priv->iso_break_stream, transfer->num_iso_packets, (PUSBD_ISO_PACKET_DESCRIPTOR)transfer->iso_packet_desc, overlapped); - } - else { + else ret = WinUSBX[sub_api].WriteIsochPipeAsap(buffer_handle, 0, out_transfer_length, !transfer_priv->iso_break_stream, overlapped); + + if (!ret && GetLastError() != ERROR_IO_PENDING) { + usbi_err(TRANSFER_CTX(transfer), "ReadIsochPipeAsap/WriteIsochPipeAsap failed: %s", windows_error_str(0)); + if (!WinUSBX[sub_api].UnregisterIsochBuffer(buffer_handle)) + usbi_warn(TRANSFER_CTX(transfer), "failed to unregister WinUSB isoch buffer: %s", windows_error_str(0)); + return LIBUSB_ERROR_IO; } // Restore the ContinueStream parameter to TRUE. transfer_priv->iso_break_stream = FALSE; - if (!ret) { - if (GetLastError() == ERROR_IO_PENDING) { - transfer_priv->isoch_buffer_handle = buffer_handle; - } else { - usbi_err(ctx, "ReadIsochPipeAsap/WriteIsochPipeAsap failed: %s", windows_error_str(0)); - if (WinUSBX[sub_api].UnregisterIsochBuffer(buffer_handle)) { - transfer_priv->isoch_buffer_handle = NULL; - return LIBUSB_ERROR_IO; - } else { - usbi_dbg("Couldn't unregister the Microsoft WinUSB isochronous buffer: %s", windows_error_str(0)); - return LIBUSB_ERROR_OTHER; - } - } - } else { - windows_force_sync_completion(overlapped, (ULONG)transfer->length); - if (!WinUSBX[sub_api].UnregisterIsochBuffer(buffer_handle)) { - usbi_dbg("Couldn't unregister the Microsoft WinUSB isochronous buffer: %s", windows_error_str(0)); - return LIBUSB_ERROR_OTHER; - } - } + transfer_priv->isoch_buffer_handle = buffer_handle; transfer_priv->interface_number = (uint8_t)current_interface; @@ -2823,27 +2719,27 @@ static int winusbx_submit_iso_transfer(int sub_api, struct usbi_transfer *itrans static int winusbx_submit_bulk_transfer(int sub_api, 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 winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); + struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer); struct winusb_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev); HANDLE winusb_handle; OVERLAPPED *overlapped; - bool ret; + BOOL ret; int current_interface; CHECK_WINUSBX_AVAILABLE(sub_api); 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"); + usbi_err(TRANSFER_CTX(transfer), "unable to match endpoint to an open interface - cancelling transfer"); return LIBUSB_ERROR_NOT_FOUND; } usbi_dbg("matched endpoint %02X with interface %d", transfer->endpoint, current_interface); - transfer_priv->handle = winusb_handle = handle_priv->interface_handle[current_interface].api_handle; - overlapped = transfer_priv->pollable_fd.overlapped; + winusb_handle = handle_priv->interface_handle[current_interface].api_handle; + set_transfer_priv_handle(itransfer, handle_priv->interface_handle[current_interface].dev_handle); + overlapped = get_transfer_priv_overlapped(itransfer); if (IS_XFERIN(transfer)) { usbi_dbg("reading %d bytes", transfer->length); @@ -2853,13 +2749,9 @@ static int winusbx_submit_bulk_transfer(int sub_api, struct usbi_transfer *itran 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)); - return LIBUSB_ERROR_IO; - } - } else { - windows_force_sync_completion(overlapped, (ULONG)transfer->length); + if (!ret && GetLastError() != ERROR_IO_PENDING) { + usbi_err(TRANSFER_CTX(transfer), "ReadPipe/WritePipe failed: %s", windows_error_str(0)); + return LIBUSB_ERROR_IO; } transfer_priv->interface_number = (uint8_t)current_interface; @@ -2869,7 +2761,6 @@ static int winusbx_submit_bulk_transfer(int sub_api, struct usbi_transfer *itran static int winusbx_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint) { - struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); struct winusb_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); struct winusb_device_priv *priv = _device_priv(dev_handle->dev); HANDLE winusb_handle; @@ -2879,7 +2770,7 @@ static int winusbx_clear_halt(int sub_api, struct libusb_device_handle *dev_hand current_interface = interface_by_endpoint(priv, handle_priv, endpoint); if (current_interface < 0) { - usbi_err(ctx, "unable to match endpoint to an open interface - cannot clear"); + usbi_err(HANDLE_CTX(dev_handle), "unable to match endpoint to an open interface - cannot clear"); return LIBUSB_ERROR_NOT_FOUND; } @@ -2887,62 +2778,29 @@ static int winusbx_clear_halt(int sub_api, struct libusb_device_handle *dev_hand winusb_handle = handle_priv->interface_handle[current_interface].api_handle; if (!WinUSBX[sub_api].ResetPipe(winusb_handle, endpoint)) { - usbi_err(ctx, "ResetPipe failed: %s", windows_error_str(0)); + usbi_err(HANDLE_CTX(dev_handle), "ResetPipe failed: %s", windows_error_str(0)); return LIBUSB_ERROR_NO_DEVICE; } return LIBUSB_SUCCESS; } -/* - * from http://www.winvistatips.com/winusb-bugchecks-t335323.html (confirmed - * through testing as well): - * "You can not call WinUsb_AbortPipe on control pipe. You can possibly cancel - * the control transfer using CancelIo" - */ -static int winusbx_abort_control(int sub_api, struct usbi_transfer *itransfer) -{ - UNUSED(sub_api); - UNUSED(itransfer); - // Cancelling of the I/O is done in the parent - return LIBUSB_SUCCESS; -} - -static int winusbx_abort_transfers(int sub_api, struct usbi_transfer *itransfer) +static int winusbx_cancel_transfer(int sub_api, 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 winusb_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); - struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); + struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer); struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev); + int current_interface = transfer_priv->interface_number; HANDLE handle; - int current_interface; CHECK_WINUSBX_AVAILABLE(sub_api); - current_interface = transfer_priv->interface_number; - 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); - if (WinUSBX[sub_api].CancelIoEx_supported) { - // Try to use CancelIoEx if available to cancel just a single transfer - handle = handle_priv->interface_handle[current_interface].dev_handle; - if (CancelIoEx(handle, transfer_priv->pollable_fd.overlapped)) - return LIBUSB_SUCCESS; - else if (GetLastError() == ERROR_NOT_FOUND) - return LIBUSB_ERROR_NOT_FOUND; - - // Not every driver implements the necessary functionality for CancelIoEx - usbi_warn(ctx, "CancelIoEx not supported for sub API %s", winusbx_driver_names[sub_api]); - WinUSBX[sub_api].CancelIoEx_supported = false; - } - 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)); + usbi_err(TRANSFER_CTX(transfer), "AbortPipe failed: %s", windows_error_str(0)); return LIBUSB_ERROR_NO_DEVICE; } @@ -2960,7 +2818,6 @@ static int winusbx_abort_transfers(int sub_api, struct usbi_transfer *itransfer) // TODO: (post hotplug): see if we can force eject the device and redetect it (reuse hotplug?) static int winusbx_reset_device(int sub_api, struct libusb_device_handle *dev_handle) { - struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); struct winusb_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); struct winusb_device_priv *priv = _device_priv(dev_handle->dev); HANDLE winusb_handle; @@ -2975,24 +2832,24 @@ static int winusbx_reset_device(int sub_api, struct libusb_device_handle *dev_ha for (j = 0; j < priv->usb_interface[i].nb_endpoints; j++) { usbi_dbg("resetting ep %02X", priv->usb_interface[i].endpoint[j]); if (!WinUSBX[sub_api].AbortPipe(winusb_handle, priv->usb_interface[i].endpoint[j])) - usbi_err(ctx, "AbortPipe (pipe address %02X) failed: %s", + usbi_err(HANDLE_CTX(dev_handle), "AbortPipe (pipe address %02X) failed: %s", priv->usb_interface[i].endpoint[j], windows_error_str(0)); // FlushPipe seems to fail on OUT pipes if (IS_EPIN(priv->usb_interface[i].endpoint[j]) && (!WinUSBX[sub_api].FlushPipe(winusb_handle, priv->usb_interface[i].endpoint[j]))) - usbi_err(ctx, "FlushPipe (pipe address %02X) failed: %s", + usbi_err(HANDLE_CTX(dev_handle), "FlushPipe (pipe address %02X) failed: %s", priv->usb_interface[i].endpoint[j], windows_error_str(0)); if (!WinUSBX[sub_api].ResetPipe(winusb_handle, priv->usb_interface[i].endpoint[j])) - usbi_err(ctx, "ResetPipe (pipe address %02X) failed: %s", + usbi_err(HANDLE_CTX(dev_handle), "ResetPipe (pipe address %02X) failed: %s", priv->usb_interface[i].endpoint[j], windows_error_str(0)); } } } // libusbK & libusb0 have the ability to issue an actual device reset - if (WinUSBX[sub_api].ResetDevice != NULL) { + if ((sub_api != SUB_API_WINUSB) && (WinUSBX[sub_api].ResetDevice != NULL)) { winusb_handle = handle_priv->interface_handle[0].api_handle; if (HANDLE_VALID(winusb_handle)) WinUSBX[sub_api].ResetDevice(winusb_handle); @@ -3001,21 +2858,17 @@ static int winusbx_reset_device(int sub_api, struct libusb_device_handle *dev_ha return LIBUSB_SUCCESS; } -static int winusbx_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size) +static enum libusb_transfer_status winusbx_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, DWORD length) { struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev); - PKISO_CONTEXT iso_context; + struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer); int i; if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) { - CHECK_WINUSBX_AVAILABLE(sub_api); - // for isochronous, need to copy the individual iso packet actual_lengths and statuses if ((sub_api == SUB_API_LIBUSBK) || (sub_api == SUB_API_LIBUSB0)) { // iso only supported on libusbk-based backends for now - iso_context = transfer_priv->iso_context; + PKISO_CONTEXT iso_context = transfer_priv->iso_context; for (i = 0; i < transfer->num_iso_packets; i++) { transfer->iso_packet_desc[i].actual_length = iso_context->IsoPackets[i].actual_length; // TODO translate USDB_STATUS codes http://msdn.microsoft.com/en-us/library/ff539136(VS.85).aspx to libusb_transfer_status @@ -3026,31 +2879,28 @@ static int winusbx_copy_transfer_data(int sub_api, struct usbi_transfer *itransf /* Convert isochronous packet descriptor between Windows and libusb representation. * Both representation are guaranteed to have the same length in bytes.*/ PUSBD_ISO_PACKET_DESCRIPTOR usbd_iso_packet_desc = (PUSBD_ISO_PACKET_DESCRIPTOR)transfer->iso_packet_desc; - for (i = 0; i < transfer->num_iso_packets; ++i) - { - int length = (i < transfer->num_iso_packets - 1) ? (usbd_iso_packet_desc[i + 1].Offset - usbd_iso_packet_desc[i].Offset) : usbd_iso_packet_desc[i].Length; - int actual_length = usbd_iso_packet_desc[i].Length; + for (i = 0; i < transfer->num_iso_packets; i++) { + unsigned int packet_length = (i < transfer->num_iso_packets - 1) ? (usbd_iso_packet_desc[i + 1].Offset - usbd_iso_packet_desc[i].Offset) : usbd_iso_packet_desc[i].Length; + unsigned int actual_length = usbd_iso_packet_desc[i].Length; USBD_STATUS status = usbd_iso_packet_desc[i].Status; - transfer->iso_packet_desc[i].length = length; + transfer->iso_packet_desc[i].length = packet_length; transfer->iso_packet_desc[i].actual_length = actual_length; transfer->iso_packet_desc[i].status = usbd_status_to_libusb_transfer_status(status); } - } - else { - for (i = 0; i < transfer->num_iso_packets; ++i) - { + } else { + for (i = 0; i < transfer->num_iso_packets; i++) { transfer->iso_packet_desc[i].status = LIBUSB_TRANSFER_COMPLETED; } } } else { // This should only occur if backend is not set correctly or other backend isoc is partially implemented PRINT_UNSUPPORTED_API(copy_transfer_data); - return LIBUSB_ERROR_NOT_SUPPORTED; + return LIBUSB_TRANSFER_ERROR; } } - itransfer->transferred += io_size; + itransfer->transferred += (int)length; return LIBUSB_TRANSFER_COMPLETED; } @@ -3072,7 +2922,7 @@ static int _hid_wcslen(WCHAR *str) return i; } -static int _hid_get_device_descriptor(struct hid_device_priv *dev, void *data, size_t *size) +static int _hid_get_device_descriptor(struct hid_device_priv *hid_priv, void *data, size_t *size) { struct libusb_device_descriptor d; @@ -3083,12 +2933,12 @@ static int _hid_get_device_descriptor(struct hid_device_priv *dev, void *data, s d.bDeviceSubClass = 0; d.bDeviceProtocol = 0; d.bMaxPacketSize0 = 64; /* fix this! */ - d.idVendor = (uint16_t)dev->vid; - d.idProduct = (uint16_t)dev->pid; + d.idVendor = (uint16_t)hid_priv->vid; + d.idProduct = (uint16_t)hid_priv->pid; d.bcdDevice = 0x0100; - d.iManufacturer = dev->string_index[0]; - d.iProduct = dev->string_index[1]; - d.iSerialNumber = dev->string_index[2]; + d.iManufacturer = hid_priv->string_index[0]; + d.iProduct = hid_priv->string_index[1]; + d.iSerialNumber = hid_priv->string_index[2]; d.bNumConfigurations = 1; if (*size > LIBUSB_DT_DEVICE_SIZE) @@ -3098,7 +2948,7 @@ static int _hid_get_device_descriptor(struct hid_device_priv *dev, void *data, s return LIBUSB_COMPLETED; } -static int _hid_get_config_descriptor(struct hid_device_priv *dev, void *data, size_t *size) +static int _hid_get_config_descriptor(struct hid_device_priv *hid_priv, void *data, size_t *size) { char num_endpoints = 0; size_t config_total_len = 0; @@ -3109,9 +2959,9 @@ static int _hid_get_config_descriptor(struct hid_device_priv *dev, void *data, s struct libusb_endpoint_descriptor *ed; size_t tmp_size; - if (dev->input_report_size) + if (hid_priv->input_report_size) num_endpoints++; - if (dev->output_report_size) + if (hid_priv->output_report_size) num_endpoints++; config_total_len = LIBUSB_DT_CONFIG_SIZE + LIBUSB_DT_INTERFACE_SIZE @@ -3145,24 +2995,24 @@ static int _hid_get_config_descriptor(struct hid_device_priv *dev, void *data, s id->iInterface = 0; tmp_size = LIBUSB_DT_HID_SIZE; - _hid_get_hid_descriptor(dev, hd, &tmp_size); + _hid_get_hid_descriptor(hid_priv, hd, &tmp_size); - if (dev->input_report_size) { + if (hid_priv->input_report_size) { ed->bLength = LIBUSB_DT_ENDPOINT_SIZE; ed->bDescriptorType = LIBUSB_DT_ENDPOINT; ed->bEndpointAddress = HID_IN_EP; ed->bmAttributes = 3; - ed->wMaxPacketSize = dev->input_report_size - 1; + ed->wMaxPacketSize = hid_priv->input_report_size - 1; ed->bInterval = 10; ed = (struct libusb_endpoint_descriptor *)((char *)ed + LIBUSB_DT_ENDPOINT_SIZE); } - if (dev->output_report_size) { + if (hid_priv->output_report_size) { ed->bLength = LIBUSB_DT_ENDPOINT_SIZE; ed->bDescriptorType = LIBUSB_DT_ENDPOINT; ed->bEndpointAddress = HID_OUT_EP; ed->bmAttributes = 3; - ed->wMaxPacketSize = dev->output_report_size - 1; + ed->wMaxPacketSize = hid_priv->output_report_size - 1; ed->bInterval = 10; } @@ -3173,7 +3023,7 @@ static int _hid_get_config_descriptor(struct hid_device_priv *dev, void *data, s return LIBUSB_COMPLETED; } -static int _hid_get_string_descriptor(struct hid_device_priv *dev, int _index, +static int _hid_get_string_descriptor(struct hid_device_priv *hid_priv, int _index, void *data, size_t *size, HANDLE hid_handle) { void *tmp = NULL; @@ -3184,17 +3034,14 @@ static int _hid_get_string_descriptor(struct hid_device_priv *dev, int _index, /* language ID, EN-US */ char string_langid[] = {0x09, 0x04}; - if ((*size < 2) || (*size > 255)) - return LIBUSB_ERROR_OVERFLOW; - if (_index == 0) { tmp = string_langid; tmp_size = sizeof(string_langid) + 2; } else { for (i = 0; i < 3; i++) { - if (_index == (dev->string_index[i])) { - tmp = dev->string[i]; - tmp_size = (_hid_wcslen(dev->string[i]) + 1) * sizeof(WCHAR); + if (_index == (hid_priv->string_index[i])) { + tmp = hid_priv->string[i]; + tmp_size = (_hid_wcslen(hid_priv->string[i]) + 1) * sizeof(WCHAR); break; } } @@ -3221,13 +3068,13 @@ static int _hid_get_string_descriptor(struct hid_device_priv *dev, int _index, return LIBUSB_COMPLETED; } -static int _hid_get_hid_descriptor(struct hid_device_priv *dev, void *data, size_t *size) +static int _hid_get_hid_descriptor(struct hid_device_priv *hid_priv, void *data, size_t *size) { struct libusb_hid_descriptor d; uint8_t tmp[MAX_HID_DESCRIPTOR_SIZE]; size_t report_len = MAX_HID_DESCRIPTOR_SIZE; - _hid_get_report_descriptor(dev, tmp, &report_len); + _hid_get_report_descriptor(hid_priv, tmp, &report_len); d.bLength = LIBUSB_DT_HID_SIZE; d.bDescriptorType = LIBUSB_DT_HID; @@ -3244,19 +3091,19 @@ static int _hid_get_hid_descriptor(struct hid_device_priv *dev, void *data, size return LIBUSB_COMPLETED; } -static int _hid_get_report_descriptor(struct hid_device_priv *dev, void *data, size_t *size) +static int _hid_get_report_descriptor(struct hid_device_priv *hid_priv, void *data, size_t *size) { uint8_t d[MAX_HID_DESCRIPTOR_SIZE]; size_t i = 0; /* usage page */ - d[i++] = 0x06; d[i++] = dev->usagePage & 0xFF; d[i++] = dev->usagePage >> 8; + d[i++] = 0x06; d[i++] = hid_priv->usagePage & 0xFF; d[i++] = hid_priv->usagePage >> 8; /* usage */ - d[i++] = 0x09; d[i++] = (uint8_t)dev->usage; + d[i++] = 0x09; d[i++] = (uint8_t)hid_priv->usage; /* start collection (application) */ d[i++] = 0xA1; d[i++] = 0x01; /* input report */ - if (dev->input_report_size) { + if (hid_priv->input_report_size) { /* usage (vendor defined) */ d[i++] = 0x09; d[i++] = 0x01; /* logical minimum (0) */ @@ -3266,12 +3113,12 @@ static int _hid_get_report_descriptor(struct hid_device_priv *dev, void *data, s /* report size (8 bits) */ d[i++] = 0x75; d[i++] = 0x08; /* report count */ - d[i++] = 0x95; d[i++] = (uint8_t)dev->input_report_size - 1; + d[i++] = 0x95; d[i++] = (uint8_t)hid_priv->input_report_size - 1; /* input (data, variable, absolute) */ d[i++] = 0x81; d[i++] = 0x00; } /* output report */ - if (dev->output_report_size) { + if (hid_priv->output_report_size) { /* usage (vendor defined) */ d[i++] = 0x09; d[i++] = 0x02; /* logical minimum (0) */ @@ -3281,12 +3128,12 @@ static int _hid_get_report_descriptor(struct hid_device_priv *dev, void *data, s /* report size (8 bits) */ d[i++] = 0x75; d[i++] = 0x08; /* report count */ - d[i++] = 0x95; d[i++] = (uint8_t)dev->output_report_size - 1; + d[i++] = 0x95; d[i++] = (uint8_t)hid_priv->output_report_size - 1; /* output (data, variable, absolute) */ d[i++] = 0x91; d[i++] = 0x00; } /* feature report */ - if (dev->feature_report_size) { + if (hid_priv->feature_report_size) { /* usage (vendor defined) */ d[i++] = 0x09; d[i++] = 0x03; /* logical minimum (0) */ @@ -3296,7 +3143,7 @@ static int _hid_get_report_descriptor(struct hid_device_priv *dev, void *data, s /* report size (8 bits) */ d[i++] = 0x75; d[i++] = 0x08; /* report count */ - d[i++] = 0x95; d[i++] = (uint8_t)dev->feature_report_size - 1; + d[i++] = 0x95; d[i++] = (uint8_t)hid_priv->feature_report_size - 1; /* feature (data, variable, absolute) */ d[i++] = 0xb2; d[i++] = 0x02; d[i++] = 0x01; } @@ -3311,32 +3158,33 @@ static int _hid_get_report_descriptor(struct hid_device_priv *dev, void *data, s return LIBUSB_COMPLETED; } -static int _hid_get_descriptor(struct hid_device_priv *dev, HANDLE hid_handle, int recipient, +static int _hid_get_descriptor(struct libusb_device *dev, HANDLE hid_handle, int recipient, int type, int _index, void *data, size_t *size) { + struct winusb_device_priv *priv = _device_priv(dev); UNUSED(recipient); switch (type) { case LIBUSB_DT_DEVICE: usbi_dbg("LIBUSB_DT_DEVICE"); - return _hid_get_device_descriptor(dev, data, size); + return _hid_get_device_descriptor(priv->hid, data, size); case LIBUSB_DT_CONFIG: usbi_dbg("LIBUSB_DT_CONFIG"); if (!_index) - return _hid_get_config_descriptor(dev, data, size); + return _hid_get_config_descriptor(priv->hid, data, size); return LIBUSB_ERROR_INVALID_PARAM; case LIBUSB_DT_STRING: usbi_dbg("LIBUSB_DT_STRING"); - return _hid_get_string_descriptor(dev, _index, data, size, hid_handle); + return _hid_get_string_descriptor(priv->hid, _index, data, size, hid_handle); case LIBUSB_DT_HID: usbi_dbg("LIBUSB_DT_HID"); if (!_index) - return _hid_get_hid_descriptor(dev, data, size); + return _hid_get_hid_descriptor(priv->hid, data, size); return LIBUSB_ERROR_INVALID_PARAM; case LIBUSB_DT_REPORT: usbi_dbg("LIBUSB_DT_REPORT"); if (!_index) - return _hid_get_report_descriptor(dev, data, size); + return _hid_get_report_descriptor(priv->hid, data, size); return LIBUSB_ERROR_INVALID_PARAM; case LIBUSB_DT_PHYSICAL: usbi_dbg("LIBUSB_DT_PHYSICAL"); @@ -3345,24 +3193,21 @@ static int _hid_get_descriptor(struct hid_device_priv *dev, HANDLE hid_handle, i return LIBUSB_ERROR_OTHER; } - usbi_dbg("unsupported"); + usbi_warn(DEVICE_CTX(dev), "unsupported"); return LIBUSB_ERROR_NOT_SUPPORTED; } -static int _hid_get_report(struct hid_device_priv *dev, HANDLE hid_handle, int id, void *data, - struct winusb_transfer_priv *tp, size_t *size, OVERLAPPED *overlapped, int report_type) +static int _hid_get_report(struct libusb_device *dev, HANDLE hid_handle, int id, void *data, + struct winusb_transfer_priv *tp, size_t size, OVERLAPPED *overlapped, int report_type) { + DWORD ioctl_code, expected_size = (DWORD)size; uint8_t *buf; - DWORD ioctl_code, read_size, expected_size = (DWORD)*size; - int r = LIBUSB_SUCCESS; - - UNUSED(dev); if (tp->hid_buffer != NULL) - usbi_dbg("program assertion failed: hid_buffer is not NULL"); + usbi_err(DEVICE_CTX(dev), "program assertion failed - hid_buffer is not NULL"); - if ((*size == 0) || (*size > MAX_HID_REPORT_SIZE)) { - usbi_dbg("invalid size (%"PRIuPTR")", (uintptr_t)*size); + if ((size == 0) || (size > MAX_HID_REPORT_SIZE)) { + usbi_warn(DEVICE_CTX(dev), "invalid size (%"PRIuPTR")", (uintptr_t)size); return LIBUSB_ERROR_INVALID_PARAM; } @@ -3374,7 +3219,7 @@ static int _hid_get_report(struct hid_device_priv *dev, HANDLE hid_handle, int i ioctl_code = IOCTL_HID_GET_FEATURE; break; default: - usbi_dbg("unknown HID report type %d", report_type); + usbi_warn(DEVICE_CTX(dev), "unknown HID report type %d", report_type); return LIBUSB_ERROR_INVALID_PARAM; } @@ -3386,64 +3231,37 @@ static int _hid_get_report(struct hid_device_priv *dev, HANDLE hid_handle, int i buf[0] = (uint8_t)id; // Must be set always usbi_dbg("report ID: 0x%02X", buf[0]); - tp->hid_expected_size = expected_size; - read_size = expected_size; - // NB: The size returned by DeviceIoControl doesn't include report IDs when not in use (0) if (!DeviceIoControl(hid_handle, ioctl_code, buf, expected_size + 1, - buf, expected_size + 1, &read_size, overlapped)) { + buf, expected_size + 1, NULL, overlapped)) { if (GetLastError() != ERROR_IO_PENDING) { - usbi_dbg("Failed to Read HID Report: %s", windows_error_str(0)); + usbi_err(DEVICE_CTX(dev), "failed to read HID Report: %s", windows_error_str(0)); free(buf); return LIBUSB_ERROR_IO; } - // Asynchronous wait - tp->hid_buffer = buf; - tp->hid_dest = data; // copy dest, as not necessarily the start of the transfer buffer - return LIBUSB_SUCCESS; } - // Transfer completed synchronously => copy and discard extra buffer - if (read_size == 0) { - usbi_warn(NULL, "program assertion failed - read completed synchronously, but no data was read"); - *size = 0; - } else { - if (buf[0] != id) - usbi_warn(NULL, "mismatched report ID (data is %02X, parameter is %02X)", buf[0], id); - - if ((size_t)read_size > expected_size) { - r = LIBUSB_ERROR_OVERFLOW; - usbi_dbg("OVERFLOW!"); - } else { - r = LIBUSB_COMPLETED; - } - - *size = MIN((size_t)read_size, *size); - if (id == 0) - memcpy(data, buf + 1, *size); // Discard report ID - else - memcpy(data, buf, *size); - } + // Asynchronous wait + tp->hid_buffer = buf; + tp->hid_dest = data; // copy dest, as not necessarily the start of the transfer buffer + tp->hid_expected_size = expected_size; - free(buf); - return r; + return LIBUSB_SUCCESS; } -static int _hid_set_report(struct hid_device_priv *dev, HANDLE hid_handle, int id, void *data, - struct winusb_transfer_priv *tp, size_t *size, OVERLAPPED *overlapped, int report_type) +static int _hid_set_report(struct libusb_device *dev, HANDLE hid_handle, int id, void *data, + struct winusb_transfer_priv *tp, size_t size, OVERLAPPED *overlapped, int report_type) { - uint8_t *buf = NULL; - DWORD ioctl_code, write_size = (DWORD)*size; + DWORD ioctl_code, write_size = (DWORD)size; // If an id is reported, we must allow MAX_HID_REPORT_SIZE + 1 size_t max_report_size = MAX_HID_REPORT_SIZE + (id ? 1 : 0); - - UNUSED(dev); + uint8_t *buf; if (tp->hid_buffer != NULL) - usbi_dbg("program assertion failed: hid_buffer is not NULL"); + usbi_err(DEVICE_CTX(dev), "program assertion failed - hid_buffer is not NULL"); - if ((*size == 0) || (*size > max_report_size)) { - usbi_dbg("invalid size (%"PRIuPTR")", (uintptr_t)*size); + if ((size == 0) || (size > max_report_size)) { + usbi_warn(DEVICE_CTX(dev), "invalid size (%"PRIuPTR")", (uintptr_t)size); return LIBUSB_ERROR_INVALID_PARAM; } @@ -3455,7 +3273,7 @@ static int _hid_set_report(struct hid_device_priv *dev, HANDLE hid_handle, int i ioctl_code = IOCTL_HID_SET_FEATURE; break; default: - usbi_dbg("unknown HID report type %d", report_type); + usbi_warn(DEVICE_CTX(dev), "unknown HID report type %d", report_type); return LIBUSB_ERROR_INVALID_PARAM; } @@ -3471,40 +3289,33 @@ static int _hid_set_report(struct hid_device_priv *dev, HANDLE hid_handle, int i if (id == 0) { buf[0] = 0; - memcpy(buf + 1, data, *size); + memcpy(buf + 1, data, size); } else { // This seems like a waste, but if we don't duplicate the // data, we'll get issues when freeing hid_buffer - memcpy(buf, data, *size); + memcpy(buf, data, size); if (buf[0] != id) - usbi_warn(NULL, "mismatched report ID (data is %02X, parameter is %02X)", buf[0], id); + usbi_warn(DEVICE_CTX(dev), "mismatched report ID (data is %02X, parameter is %02X)", buf[0], id); } // NB: The size returned by DeviceIoControl doesn't include report IDs when not in use (0) if (!DeviceIoControl(hid_handle, ioctl_code, buf, write_size, - buf, write_size, &write_size, overlapped)) { + buf, write_size, NULL, overlapped)) { if (GetLastError() != ERROR_IO_PENDING) { - usbi_dbg("Failed to Write HID Output Report: %s", windows_error_str(0)); + usbi_err(DEVICE_CTX(dev), "failed to write HID Output Report: %s", windows_error_str(0)); free(buf); return LIBUSB_ERROR_IO; } - tp->hid_buffer = buf; - tp->hid_dest = NULL; - return LIBUSB_SUCCESS; } - // Transfer completed synchronously - *size = write_size; - if (write_size == 0) - usbi_dbg("program assertion failed - write completed synchronously, but no data was written"); - - free(buf); - return LIBUSB_COMPLETED; + tp->hid_buffer = buf; + tp->hid_dest = NULL; + return LIBUSB_SUCCESS; } -static int _hid_class_request(struct hid_device_priv *dev, HANDLE hid_handle, int request_type, +static int _hid_class_request(struct libusb_device *dev, HANDLE hid_handle, int request_type, int request, int value, int _index, void *data, struct winusb_transfer_priv *tp, - size_t *size, OVERLAPPED *overlapped) + size_t size, OVERLAPPED *overlapped) { int report_type = (value >> 8) & 0xFF; int report_id = value & 0xFF; @@ -3524,32 +3335,30 @@ static int _hid_class_request(struct hid_device_priv *dev, HANDLE hid_handle, in return LIBUSB_ERROR_INVALID_PARAM; } - /* * HID API functions */ -static int hid_init(struct libusb_context *ctx) +static bool hid_init(struct libusb_context *ctx) { UNUSED(ctx); DLL_GET_HANDLE(hid); - DLL_LOAD_FUNC(hid, HidD_GetAttributes, TRUE); - DLL_LOAD_FUNC(hid, HidD_GetHidGuid, TRUE); - DLL_LOAD_FUNC(hid, HidD_GetPreparsedData, TRUE); - DLL_LOAD_FUNC(hid, HidD_FreePreparsedData, TRUE); - DLL_LOAD_FUNC(hid, HidD_GetManufacturerString, TRUE); - DLL_LOAD_FUNC(hid, HidD_GetProductString, TRUE); - DLL_LOAD_FUNC(hid, HidD_GetSerialNumberString, TRUE); - DLL_LOAD_FUNC(hid, HidD_GetIndexedString, TRUE); - DLL_LOAD_FUNC(hid, HidP_GetCaps, TRUE); - DLL_LOAD_FUNC(hid, HidD_SetNumInputBuffers, TRUE); - DLL_LOAD_FUNC(hid, HidD_GetPhysicalDescriptor, TRUE); - DLL_LOAD_FUNC(hid, HidD_FlushQueue, TRUE); - DLL_LOAD_FUNC(hid, HidP_GetValueCaps, TRUE); - - api_hid_available = true; - return LIBUSB_SUCCESS; + DLL_LOAD_FUNC(hid, HidD_GetAttributes, true); + DLL_LOAD_FUNC(hid, HidD_GetHidGuid, true); + DLL_LOAD_FUNC(hid, HidD_GetPreparsedData, true); + DLL_LOAD_FUNC(hid, HidD_FreePreparsedData, true); + DLL_LOAD_FUNC(hid, HidD_GetManufacturerString, true); + DLL_LOAD_FUNC(hid, HidD_GetProductString, true); + DLL_LOAD_FUNC(hid, HidD_GetSerialNumberString, true); + DLL_LOAD_FUNC(hid, HidD_GetIndexedString, true); + DLL_LOAD_FUNC(hid, HidP_GetCaps, true); + DLL_LOAD_FUNC(hid, HidD_SetNumInputBuffers, true); + DLL_LOAD_FUNC(hid, HidD_GetPhysicalDescriptor, true); + DLL_LOAD_FUNC(hid, HidD_FlushQueue, true); + DLL_LOAD_FUNC(hid, HidP_GetValueCaps, true); + + return true; } static void hid_exit(void) @@ -3562,7 +3371,6 @@ static void hid_exit(void) // composite_open(), with interfaces belonging to different APIs static int hid_open(int sub_api, struct libusb_device_handle *dev_handle) { - struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); struct winusb_device_priv *priv = _device_priv(dev_handle->dev); struct winusb_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); HIDD_ATTRIBUTES hid_attributes; @@ -3582,7 +3390,7 @@ static int hid_open(int sub_api, struct libusb_device_handle *dev_handle) CHECK_HID_AVAILABLE; if (priv->hid == NULL) { - usbi_err(ctx, "program assertion failed - private HID structure is unitialized"); + usbi_err(HANDLE_CTX(dev_handle), "program assertion failed - private HID structure is unitialized"); return LIBUSB_ERROR_NOT_FOUND; } @@ -3590,7 +3398,7 @@ static int hid_open(int sub_api, struct libusb_device_handle *dev_handle) if ((priv->usb_interface[i].path != NULL) && (priv->usb_interface[i].apib->id == USB_API_HID)) { hid_handle = CreateFileA(priv->usb_interface[i].path, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, - NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); + NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); /* * http://www.lvr.com/hidfaq.htm: Why do I receive "Access denied" when attempting to access my HID? * "Windows 2000 and later have exclusive read/write access to HIDs that are configured as a system @@ -3599,11 +3407,11 @@ static int hid_open(int sub_api, struct libusb_device_handle *dev_handle) * HidD_GetFeature (if the device supports Feature reports)." */ if (hid_handle == INVALID_HANDLE_VALUE) { - usbi_warn(ctx, "could not open HID device in R/W mode (keyboard or mouse?) - trying without"); + usbi_warn(HANDLE_CTX(dev_handle), "could not open HID device in R/W mode (keyboard or mouse?) - trying without"); hid_handle = CreateFileA(priv->usb_interface[i].path, 0, FILE_SHARE_WRITE | FILE_SHARE_READ, - NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); + NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); if (hid_handle == INVALID_HANDLE_VALUE) { - usbi_err(ctx, "could not open device %s (interface %d): %s", priv->path, i, windows_error_str(0)); + usbi_err(HANDLE_CTX(dev_handle), "could not open device %s (interface %d): %s", priv->path, i, windows_error_str(0)); switch (GetLastError()) { case ERROR_FILE_NOT_FOUND: // The device was disconnected return LIBUSB_ERROR_NO_DEVICE; @@ -3622,7 +3430,7 @@ static int hid_open(int sub_api, struct libusb_device_handle *dev_handle) hid_attributes.Size = sizeof(hid_attributes); do { if (!HidD_GetAttributes(hid_handle, &hid_attributes)) { - usbi_err(ctx, "could not gain access to HID top collection (HidD_GetAttributes)"); + usbi_err(HANDLE_CTX(dev_handle), "could not gain access to HID top collection (HidD_GetAttributes)"); break; } @@ -3635,11 +3443,11 @@ static int hid_open(int sub_api, struct libusb_device_handle *dev_handle) // Get the maximum input and output report size if (!HidD_GetPreparsedData(hid_handle, &preparsed_data) || !preparsed_data) { - usbi_err(ctx, "could not read HID preparsed data (HidD_GetPreparsedData)"); + usbi_err(HANDLE_CTX(dev_handle), "could not read HID preparsed data (HidD_GetPreparsedData)"); break; } if (HidP_GetCaps(preparsed_data, &capabilities) != HIDP_STATUS_SUCCESS) { - usbi_err(ctx, "could not parse HID capabilities (HidP_GetCaps)"); + usbi_err(HANDLE_CTX(dev_handle), "could not parse HID capabilities (HidP_GetCaps)"); break; } @@ -3666,12 +3474,12 @@ static int hid_open(int sub_api, struct libusb_device_handle *dev_handle) } if (nb_ids[1] != 0) { if (nb_ids[0] != 0) - usbi_warn(ctx, "program assertion failed: zero and nonzero report IDs used for %s", + usbi_warn(HANDLE_CTX(dev_handle), "program assertion failed - zero and nonzero report IDs used for %s", type[j]); priv->hid->uses_report_ids[j] = true; } } else { - usbi_warn(ctx, " could not process %s report IDs", type[j]); + usbi_warn(HANDLE_CTX(dev_handle), " could not process %s report IDs", type[j]); } free(value_caps); } @@ -3720,7 +3528,8 @@ static void hid_close(int sub_api, struct libusb_device_handle *dev_handle) int i; UNUSED(sub_api); - if (!api_hid_available) + + if (DLL_HANDLE_NAME(hid) == NULL) return; for (i = 0; i < USB_MAXINTERFACES; i++) { @@ -3777,8 +3586,6 @@ static int hid_release_interface(int sub_api, struct libusb_device_handle *dev_h static int hid_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting) { - struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); - UNUSED(sub_api); UNUSED(iface); @@ -3788,7 +3595,7 @@ static int hid_set_interface_altsetting(int sub_api, struct libusb_device_handle return LIBUSB_ERROR_INVALID_PARAM; if (altsetting != 0) { - usbi_err(ctx, "set interface altsetting not supported for altsetting >0"); + usbi_err(HANDLE_CTX(dev_handle), "set interface altsetting not supported for altsetting >0"); return LIBUSB_ERROR_NOT_SUPPORTED; } @@ -3798,10 +3605,10 @@ static int hid_set_interface_altsetting(int sub_api, struct libusb_device_handle static int hid_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer) { struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - struct winusb_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); + struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer); + struct libusb_device_handle *dev_handle = transfer->dev_handle; + struct winusb_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev); - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); WINUSB_SETUP_PACKET *setup = (WINUSB_SETUP_PACKET *)transfer->buffer; HANDLE hid_handle; OVERLAPPED *overlapped; @@ -3819,7 +3626,7 @@ static int hid_submit_control_transfer(int sub_api, struct usbi_transfer *itrans if (size > MAX_CTRL_BUFFER_LENGTH) return LIBUSB_ERROR_INVALID_PARAM; - current_interface = get_valid_interface(transfer->dev_handle, USB_API_HID); + current_interface = get_valid_interface(dev_handle, USB_API_HID); if (current_interface < 0) { if (auto_claim(transfer, ¤t_interface, USB_API_HID) != LIBUSB_SUCCESS) return LIBUSB_ERROR_NOT_FOUND; @@ -3828,17 +3635,18 @@ 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; - overlapped = transfer_priv->pollable_fd.overlapped; + set_transfer_priv_handle(itransfer, hid_handle); + overlapped = get_transfer_priv_overlapped(itransfer); 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, hid_handle, LIBUSB_REQ_RECIPIENT(setup->RequestType), + r = _hid_get_descriptor(dev_handle->dev, 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: - r = winusb_get_configuration(transfer->dev_handle, &config); + r = winusb_get_configuration(dev_handle, &config); if (r == LIBUSB_SUCCESS) { size = 1; ((uint8_t *)transfer->buffer)[LIBUSB_CONTROL_SETUP_SIZE] = (uint8_t)config; @@ -3849,7 +3657,7 @@ static int hid_submit_control_transfer(int sub_api, struct usbi_transfer *itrans if (setup->Value == priv->active_config) { r = LIBUSB_COMPLETED; } else { - usbi_warn(ctx, "cannot set configuration other than the default one"); + usbi_warn(TRANSFER_CTX(transfer), "cannot set configuration other than the default one"); r = LIBUSB_ERROR_NOT_SUPPORTED; } break; @@ -3859,22 +3667,22 @@ static int hid_submit_control_transfer(int sub_api, struct usbi_transfer *itrans r = LIBUSB_COMPLETED; break; case LIBUSB_REQUEST_SET_INTERFACE: - r = hid_set_interface_altsetting(0, transfer->dev_handle, setup->Index, setup->Value); + r = hid_set_interface_altsetting(0, dev_handle, setup->Index, setup->Value); if (r == LIBUSB_SUCCESS) r = LIBUSB_COMPLETED; break; default: - usbi_warn(ctx, "unsupported HID control request"); + usbi_warn(TRANSFER_CTX(transfer), "unsupported HID control request"); return LIBUSB_ERROR_NOT_SUPPORTED; } break; case LIBUSB_REQUEST_TYPE_CLASS: - r = _hid_class_request(priv->hid, hid_handle, setup->RequestType, setup->Request, setup->Value, + r = _hid_class_request(dev_handle->dev, hid_handle, setup->RequestType, setup->Request, setup->Value, setup->Index, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, transfer_priv, - &size, overlapped); + size, overlapped); break; default: - usbi_warn(ctx, "unsupported HID control request"); + usbi_warn(TRANSFER_CTX(transfer), "unsupported HID control request"); return LIBUSB_ERROR_NOT_SUPPORTED; } @@ -3895,16 +3703,14 @@ static int hid_submit_control_transfer(int sub_api, struct usbi_transfer *itrans static int hid_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer) { struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); + struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer); struct winusb_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev); HANDLE hid_handle; OVERLAPPED *overlapped; - bool direction_in, ret; + bool direction_in; + BOOL ret; int current_interface, length; - DWORD size; - int r = LIBUSB_SUCCESS; UNUSED(sub_api); CHECK_HID_AVAILABLE; @@ -3914,14 +3720,15 @@ static int hid_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer 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"); + usbi_err(TRANSFER_CTX(transfer), "unable to match endpoint to an open interface - cancelling transfer"); return LIBUSB_ERROR_NOT_FOUND; } usbi_dbg("matched endpoint %02X with interface %d", transfer->endpoint, current_interface); - transfer_priv->handle = hid_handle = handle_priv->interface_handle[current_interface].api_handle; - overlapped = transfer_priv->pollable_fd.overlapped; + hid_handle = handle_priv->interface_handle[current_interface].api_handle; + set_transfer_priv_handle(itransfer, hid_handle); + overlapped = get_transfer_priv_overlapped(itransfer); direction_in = IS_XFERIN(transfer); // If report IDs are not in use, an extra prefix byte must be added @@ -3941,7 +3748,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(hid_handle, transfer_priv->hid_buffer, length + 1, &size, overlapped); + ret = ReadFile(hid_handle, transfer_priv->hid_buffer, length + 1, NULL, overlapped); } else { if (!priv->hid->uses_report_ids[1]) memcpy(transfer_priv->hid_buffer + 1, transfer->buffer, transfer->length); @@ -3950,64 +3757,18 @@ 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(hid_handle, transfer_priv->hid_buffer, length, &size, overlapped); + ret = WriteFile(hid_handle, transfer_priv->hid_buffer, length, NULL, overlapped); } - if (!ret) { - if (GetLastError() != ERROR_IO_PENDING) { - usbi_err(ctx, "HID transfer failed: %s", windows_error_str(0)); - safe_free(transfer_priv->hid_buffer); - return LIBUSB_ERROR_IO; - } - } else { - // Only write operations that completed synchronously need to free up - // hid_buffer. For reads, copy_transfer_data() handles that process. - if (!direction_in) - safe_free(transfer_priv->hid_buffer); - - if (size == 0) { - usbi_err(ctx, "program assertion failed - no data was transferred"); - size = 1; - } - if (size > (size_t)length) { - usbi_err(ctx, "OVERFLOW!"); - r = LIBUSB_ERROR_OVERFLOW; - } - windows_force_sync_completion(overlapped, (ULONG)size); + if (!ret && GetLastError() != ERROR_IO_PENDING) { + usbi_err(TRANSFER_CTX(transfer), "HID transfer failed: %s", windows_error_str(0)); + safe_free(transfer_priv->hid_buffer); + return LIBUSB_ERROR_IO; } transfer_priv->interface_number = (uint8_t)current_interface; - return r; -} - -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 winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - struct winusb_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); - HANDLE hid_handle; - int current_interface; - - UNUSED(sub_api); - CHECK_HID_AVAILABLE; - - current_interface = transfer_priv->interface_number; - 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); - - hid_handle = handle_priv->interface_handle[current_interface].api_handle; - - // Use CancelIoEx to cancel just a single transfer - if (CancelIoEx(hid_handle, transfer_priv->pollable_fd.overlapped)) - return LIBUSB_SUCCESS; - - usbi_warn(ctx, "CancelIoEx failed: %s", windows_error_str(0)); - return LIBUSB_ERROR_NOT_FOUND; + return LIBUSB_SUCCESS; } static int hid_reset_device(int sub_api, struct libusb_device_handle *dev_handle) @@ -4031,7 +3792,6 @@ static int hid_reset_device(int sub_api, struct libusb_device_handle *dev_handle static int hid_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint) { - struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); struct winusb_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); struct winusb_device_priv *priv = _device_priv(dev_handle->dev); HANDLE hid_handle; @@ -4042,7 +3802,7 @@ static int hid_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, current_interface = interface_by_endpoint(priv, handle_priv, endpoint); if (current_interface < 0) { - usbi_err(ctx, "unable to match endpoint to an open interface - cannot clear"); + usbi_err(HANDLE_CTX(dev_handle), "unable to match endpoint to an open interface - cannot clear"); return LIBUSB_ERROR_NOT_FOUND; } @@ -4052,7 +3812,7 @@ static int hid_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, // No endpoint selection with Microsoft's implementation, so we try to flush the // whole interface. Should be OK for most case scenarios if (!HidD_FlushQueue(hid_handle)) { - usbi_err(ctx, "Flushing of HID queue failed: %s", windows_error_str(0)); + usbi_err(HANDLE_CTX(dev_handle), "Flushing of HID queue failed: %s", windows_error_str(0)); // Device was probably disconnected return LIBUSB_ERROR_NO_DEVICE; } @@ -4061,33 +3821,31 @@ static int hid_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, } // This extra function is only needed for HID -static int hid_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size) +static enum libusb_transfer_status hid_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, DWORD length) { struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); - struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - int r = LIBUSB_TRANSFER_COMPLETED; - uint32_t corrected_size = io_size; + struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer); + enum libusb_transfer_status r = LIBUSB_TRANSFER_COMPLETED; UNUSED(sub_api); if (transfer_priv->hid_buffer != NULL) { // If we have a valid hid_buffer, it means the transfer was async if (transfer_priv->hid_dest != NULL) { // Data readout - if (corrected_size > 0) { + if (length > 0) { // First, check for overflow - if (corrected_size > transfer_priv->hid_expected_size) { - usbi_err(ctx, "OVERFLOW!"); - corrected_size = (uint32_t)transfer_priv->hid_expected_size; + if ((size_t)length > transfer_priv->hid_expected_size) { + usbi_err(TRANSFER_CTX(transfer), "OVERFLOW!"); + length = (DWORD)transfer_priv->hid_expected_size; r = LIBUSB_TRANSFER_OVERFLOW; } if (transfer_priv->hid_buffer[0] == 0) { // Discard the 1 byte report ID prefix - corrected_size--; - memcpy(transfer_priv->hid_dest, transfer_priv->hid_buffer + 1, corrected_size); + length--; + memcpy(transfer_priv->hid_dest, transfer_priv->hid_buffer + 1, length); } else { - memcpy(transfer_priv->hid_dest, transfer_priv->hid_buffer, corrected_size); + memcpy(transfer_priv->hid_dest, transfer_priv->hid_buffer, length); } } transfer_priv->hid_dest = NULL; @@ -4096,7 +3854,7 @@ static int hid_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, safe_free(transfer_priv->hid_buffer); } - itransfer->transferred += corrected_size; + itransfer->transferred += (int)length; return r; } @@ -4107,13 +3865,15 @@ static int hid_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, static int composite_open(int sub_api, struct libusb_device_handle *dev_handle) { struct winusb_device_priv *priv = _device_priv(dev_handle->dev); - int r = LIBUSB_ERROR_NOT_FOUND; - uint8_t i; + int i, r = LIBUSB_ERROR_NOT_FOUND; // SUB_API_MAX + 1 as the SUB_API_MAX pos is used to indicate availability of HID - bool available[SUB_API_MAX + 1] = { 0 }; + bool available[SUB_API_MAX + 1]; UNUSED(sub_api); + for (i = 0; i < SUB_API_MAX + 1; i++) + available[i] = false; + for (i = 0; i < USB_MAXINTERFACES; i++) { switch (priv->usb_interface[i].apib->id) { case USB_API_WINUSBX: @@ -4154,12 +3914,15 @@ static int composite_open(int sub_api, struct libusb_device_handle *dev_handle) static void composite_close(int sub_api, struct libusb_device_handle *dev_handle) { struct winusb_device_priv *priv = _device_priv(dev_handle->dev); - uint8_t i; + int i; // SUB_API_MAX + 1 as the SUB_API_MAX pos is used to indicate availability of HID - bool available[SUB_API_MAX + 1] = { 0 }; + bool available[SUB_API_MAX + 1]; UNUSED(sub_api); + for (i = 0; i < SUB_API_MAX + 1; i++) + available[i] = false; + for (i = 0; i < USB_MAXINTERFACES; i++) { switch (priv->usb_interface[i].apib->id) { case USB_API_WINUSBX: @@ -4219,7 +3982,6 @@ static int composite_release_interface(int sub_api, struct libusb_device_handle static int composite_submit_control_transfer(int sub_api, 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 winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev); struct libusb_config_descriptor *conf_desc; WINUSB_SETUP_PACKET *setup = (WINUSB_SETUP_PACKET *)transfer->buffer; @@ -4278,13 +4040,13 @@ static int composite_submit_control_transfer(int sub_api, struct usbi_transfer * } } - usbi_err(ctx, "no libusb supported interfaces to complete request"); + usbi_err(TRANSFER_CTX(transfer), "no libusb supported interfaces to complete request"); return LIBUSB_ERROR_NOT_FOUND; } -static int composite_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer) { +static int composite_submit_bulk_transfer(int sub_api, 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 winusb_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev); int current_interface; @@ -4293,7 +4055,7 @@ static int composite_submit_bulk_transfer(int sub_api, struct usbi_transfer *itr 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"); + usbi_err(TRANSFER_CTX(transfer), "unable to match endpoint to an open interface - cancelling transfer"); return LIBUSB_ERROR_NOT_FOUND; } @@ -4303,9 +4065,9 @@ static int composite_submit_bulk_transfer(int sub_api, struct usbi_transfer *itr submit_bulk_transfer(priv->usb_interface[current_interface].sub_api, itransfer); } -static int composite_submit_iso_transfer(int sub_api, struct usbi_transfer *itransfer) { +static int composite_submit_iso_transfer(int sub_api, 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 winusb_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev); int current_interface; @@ -4314,7 +4076,7 @@ static int composite_submit_iso_transfer(int sub_api, struct usbi_transfer *itra 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"); + usbi_err(TRANSFER_CTX(transfer), "unable to match endpoint to an open interface - cancelling transfer"); return LIBUSB_ERROR_NOT_FOUND; } @@ -4326,7 +4088,6 @@ static int composite_submit_iso_transfer(int sub_api, struct usbi_transfer *itra static int composite_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint) { - struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); struct winusb_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); struct winusb_device_priv *priv = _device_priv(dev_handle->dev); int current_interface; @@ -4335,7 +4096,7 @@ static int composite_clear_halt(int sub_api, struct libusb_device_handle *dev_ha current_interface = interface_by_endpoint(priv, handle_priv, endpoint); if (current_interface < 0) { - usbi_err(ctx, "unable to match endpoint to an open interface - cannot clear"); + usbi_err(HANDLE_CTX(dev_handle), "unable to match endpoint to an open interface - cannot clear"); return LIBUSB_ERROR_NOT_FOUND; } @@ -4345,51 +4106,30 @@ static int composite_clear_halt(int sub_api, struct libusb_device_handle *dev_ha clear_halt(priv->usb_interface[current_interface].sub_api, dev_handle, endpoint); } -static int composite_abort_control(int sub_api, struct usbi_transfer *itransfer) +static int composite_cancel_transfer(int sub_api, struct usbi_transfer *itransfer) { struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); + struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer); struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev); int current_interface = transfer_priv->interface_number; UNUSED(sub_api); if ((current_interface < 0) || (current_interface >= USB_MAXINTERFACES)) { - usbi_err(TRANSFER_CTX(transfer), "program assertion failed: invalid interface_number"); + usbi_err(TRANSFER_CTX(transfer), "program assertion failed - invalid interface_number"); return LIBUSB_ERROR_NOT_FOUND; } - CHECK_SUPPORTED_API(priv->usb_interface[current_interface].apib, abort_control); + CHECK_SUPPORTED_API(priv->usb_interface[current_interface].apib, cancel_transfer); 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) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev); - int current_interface = transfer_priv->interface_number; - - UNUSED(sub_api); - - if ((current_interface < 0) || (current_interface >= USB_MAXINTERFACES)) { - usbi_err(TRANSFER_CTX(transfer), "program assertion failed: invalid interface_number"); - return LIBUSB_ERROR_NOT_FOUND; - } - - CHECK_SUPPORTED_API(priv->usb_interface[current_interface].apib, abort_transfers); - - return priv->usb_interface[current_interface].apib-> - abort_transfers(priv->usb_interface[current_interface].sub_api, itransfer); + cancel_transfer(priv->usb_interface[current_interface].sub_api, itransfer); } static int composite_reset_device(int sub_api, struct libusb_device_handle *dev_handle) { struct winusb_device_priv *priv = _device_priv(dev_handle->dev); - int r; - uint8_t i; + int i, r; bool available[SUB_API_MAX]; UNUSED(sub_api); @@ -4414,16 +4154,19 @@ static int composite_reset_device(int sub_api, struct libusb_device_handle *dev_ return LIBUSB_SUCCESS; } -static int composite_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size) +static enum libusb_transfer_status composite_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, DWORD length) { struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); + struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer); struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev); int current_interface = transfer_priv->interface_number; UNUSED(sub_api); - CHECK_SUPPORTED_API(priv->usb_interface[current_interface].apib, copy_transfer_data); + if (priv->usb_interface[current_interface].apib->copy_transfer_data == NULL) { + usbi_err(TRANSFER_CTX(transfer), "program assertion failed - no function to copy transfer data"); + return LIBUSB_TRANSFER_ERROR; + } return priv->usb_interface[current_interface].apib-> - copy_transfer_data(priv->usb_interface[current_interface].sub_api, itransfer, io_size); + copy_transfer_data(priv->usb_interface[current_interface].sub_api, itransfer, length); } diff --git a/libusb/os/windows_winusb.h b/libusb/os/windows_winusb.h index 6ac39c3..57d4b7f 100644 --- a/libusb/os/windows_winusb.h +++ b/libusb/os/windows_winusb.h @@ -69,6 +69,8 @@ const GUID GUID_DEVINTERFACE_USB_HUB = {0xF18A0E88, 0xC30C, 0x11D0, {0x88, 0x15, const GUID GUID_DEVINTERFACE_LIBUSB0_FILTER = {0xF9F3FF14, 0xAE21, 0x48A0, {0x8A, 0x25, 0x80, 0x11, 0xA7, 0xA9, 0x31, 0xD9}}; #endif +// The following define MUST be == sizeof(USB_DESCRIPTOR_REQUEST) +#define USB_DESCRIPTOR_REQUEST_SIZE 12U /* * Multiple USB API backend support @@ -93,7 +95,7 @@ struct windows_usb_api_backend { const char * const designation; const char * const * const driver_name_list; // Driver name, without .sys, e.g. "usbccgp" const uint8_t nb_driver_names; - int (*init)(struct libusb_context *ctx); + bool (*init)(struct libusb_context *ctx); void (*exit)(void); int (*open)(int sub_api, struct libusb_device_handle *dev_handle); void (*close)(int sub_api, struct libusb_device_handle *dev_handle); @@ -106,9 +108,8 @@ struct windows_usb_api_backend { int (*submit_bulk_transfer)(int sub_api, struct usbi_transfer *itransfer); int (*submit_iso_transfer)(int sub_api, struct usbi_transfer *itransfer); int (*submit_control_transfer)(int sub_api, struct usbi_transfer *itransfer); - int (*abort_control)(int sub_api, struct usbi_transfer *itransfer); - int (*abort_transfers)(int sub_api, struct usbi_transfer *itransfer); - int (*copy_transfer_data)(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size); + int (*cancel_transfer)(int sub_api, struct usbi_transfer *itransfer); + enum libusb_transfer_status (*copy_transfer_data)(int sub_api, struct usbi_transfer *itransfer, DWORD length); }; extern const struct windows_usb_api_backend usb_api_backend[USB_API_MAX]; @@ -226,8 +227,11 @@ static inline void winusb_device_priv_release(struct libusb_device *dev) free(p->dev_id); free(p->path); if ((dev->num_configurations > 0) && (p->config_descriptor != NULL)) { - for (i = 0; i < dev->num_configurations; i++) - free(p->config_descriptor[i]); + for (i = 0; i < dev->num_configurations; i++) { + if (p->config_descriptor[i] == NULL) + continue; + free((UCHAR *)p->config_descriptor[i] - USB_DESCRIPTOR_REQUEST_SIZE); + } } free(p->config_descriptor); free(p->hid); @@ -422,6 +426,12 @@ typedef struct _USB_NODE_CONNECTION_INFORMATION_EX_V2 { /* libusbK */ #define ISO_ALWAYS_START_ASAP 0x21 +typedef struct _USBD_ISO_PACKET_DESCRIPTOR { + ULONG Offset; + ULONG Length; + USBD_STATUS Status; +} USBD_ISO_PACKET_DESCRIPTOR, *PUSBD_ISO_PACKET_DESCRIPTOR; + typedef enum _USBD_PIPE_TYPE { UsbdPipeTypeControl, UsbdPipeTypeIsochronous, @@ -429,6 +439,14 @@ typedef enum _USBD_PIPE_TYPE { UsbdPipeTypeInterrupt } USBD_PIPE_TYPE; +typedef struct { + USBD_PIPE_TYPE PipeType; + UCHAR PipeId; + USHORT MaximumPacketSize; + UCHAR Interval; + ULONG MaximumBytesPerInterval; +} WINUSB_PIPE_INFORMATION_EX, *PWINUSB_PIPE_INFORMATION_EX; + #include <pshpack1.h> typedef struct _WINUSB_SETUP_PACKET { @@ -441,7 +459,8 @@ typedef struct _WINUSB_SETUP_PACKET { #include <poppack.h> -typedef void *WINUSB_INTERFACE_HANDLE, *PWINUSB_INTERFACE_HANDLE; +typedef PVOID WINUSB_INTERFACE_HANDLE, *PWINUSB_INTERFACE_HANDLE; +typedef PVOID WINUSB_ISOCH_BUFFER_HANDLE, *PWINUSB_ISOCH_BUFFER_HANDLE; typedef BOOL (WINAPI *WinUsb_AbortPipe_t)( WINUSB_INTERFACE_HANDLE InterfaceHandle, @@ -471,6 +490,21 @@ typedef BOOL (WINAPI *WinUsb_Initialize_t)( HANDLE DeviceHandle, PWINUSB_INTERFACE_HANDLE InterfaceHandle ); +typedef BOOL (WINAPI *WinUsb_QueryPipeEx_t)( + WINUSB_INTERFACE_HANDLE InterfaceHandle, + UCHAR AlternateInterfaceHandle, + UCHAR PipeIndex, + PWINUSB_PIPE_INFORMATION_EX PipeInformationEx +); +typedef BOOL (WINAPI *WinUsb_ReadIsochPipeAsap_t)( + PWINUSB_ISOCH_BUFFER_HANDLE BufferHandle, + ULONG Offset, + ULONG Length, + BOOL ContinueStream, + ULONG NumberOfPackets, + PUSBD_ISO_PACKET_DESCRIPTOR IsoPacketDescriptors, + LPOVERLAPPED Overlapped +); typedef BOOL (WINAPI *WinUsb_ReadPipe_t)( WINUSB_INTERFACE_HANDLE InterfaceHandle, UCHAR PipeID, @@ -479,8 +513,12 @@ typedef BOOL (WINAPI *WinUsb_ReadPipe_t)( PULONG LengthTransferred, LPOVERLAPPED Overlapped ); -typedef BOOL (WINAPI *WinUsb_ResetDevice_t)( - WINUSB_INTERFACE_HANDLE InterfaceHandle +typedef BOOL (WINAPI *WinUsb_RegisterIsochBuffer_t)( + WINUSB_INTERFACE_HANDLE InterfaceHandle, + UCHAR PipeID, + PVOID Buffer, + ULONG BufferLength, + PWINUSB_ISOCH_BUFFER_HANDLE BufferHandle ); typedef BOOL (WINAPI *WinUsb_ResetPipe_t)( WINUSB_INTERFACE_HANDLE InterfaceHandle, @@ -497,29 +535,9 @@ typedef BOOL (WINAPI *WinUsb_SetPipePolicy_t)( ULONG ValueLength, PVOID Value ); -typedef BOOL (WINAPI *WinUsb_WritePipe_t)( - WINUSB_INTERFACE_HANDLE InterfaceHandle, - UCHAR PipeID, - PUCHAR Buffer, - ULONG BufferLength, - PULONG LengthTransferred, - LPOVERLAPPED Overlapped -); - -typedef PVOID WINUSB_ISOCH_BUFFER_HANDLE, *PWINUSB_ISOCH_BUFFER_HANDLE; - -typedef BOOL (WINAPI *WinUsb_RegisterIsochBuffer_t)( - WINUSB_INTERFACE_HANDLE InterfaceHandle, - UCHAR PipeID, - PVOID Buffer, - ULONG BufferLength, - PWINUSB_ISOCH_BUFFER_HANDLE BufferHandle -); - typedef BOOL (WINAPI *WinUsb_UnregisterIsochBuffer_t)( WINUSB_ISOCH_BUFFER_HANDLE BufferHandle ); - typedef BOOL (WINAPI *WinUsb_WriteIsochPipeAsap_t)( WINUSB_ISOCH_BUFFER_HANDLE BufferHandle, ULONG Offset, @@ -527,37 +545,13 @@ typedef BOOL (WINAPI *WinUsb_WriteIsochPipeAsap_t)( BOOL ContinueStream, LPOVERLAPPED Overlapped ); - -typedef LONG USBD_STATUS; -typedef struct { - ULONG Offset; - ULONG Length; - USBD_STATUS Status; -} USBD_ISO_PACKET_DESCRIPTOR, *PUSBD_ISO_PACKET_DESCRIPTOR; - -typedef BOOL (WINAPI *WinUsb_ReadIsochPipeAsap_t)( - PWINUSB_ISOCH_BUFFER_HANDLE BufferHandle, - ULONG Offset, - ULONG Length, - BOOL ContinueStream, - ULONG NumberOfPackets, - PUSBD_ISO_PACKET_DESCRIPTOR IsoPacketDescriptors, - LPOVERLAPPED Overlapped -); - -typedef struct { - USBD_PIPE_TYPE PipeType; - UCHAR PipeId; - USHORT MaximumPacketSize; - UCHAR Interval; - ULONG MaximumBytesPerInterval; -} WINUSB_PIPE_INFORMATION_EX, *PWINUSB_PIPE_INFORMATION_EX; - -typedef BOOL (WINAPI *WinUsb_QueryPipeEx_t)( +typedef BOOL (WINAPI *WinUsb_WritePipe_t)( WINUSB_INTERFACE_HANDLE InterfaceHandle, - UCHAR AlternateInterfaceHandle, - UCHAR PipeIndex, - PWINUSB_PIPE_INFORMATION_EX PipeInformationEx + UCHAR PipeID, + PUCHAR Buffer, + ULONG BufferLength, + PULONG LengthTransferred, + LPOVERLAPPED Overlapped ); /* /!\ These must match the ones from the official libusbk.h */ @@ -607,15 +601,19 @@ typedef struct _KLIB_VERSION { } KLIB_VERSION, *PKLIB_VERSION; typedef BOOL (WINAPI *LibK_GetProcAddress_t)( - PVOID *ProcAddress, - ULONG DriverID, - ULONG FunctionID + PVOID ProcAddress, + INT DriverID, + INT FunctionID ); typedef VOID (WINAPI *LibK_GetVersion_t)( PKLIB_VERSION Version ); +typedef BOOL (WINAPI *LibK_ResetDevice_t)( + WINUSB_INTERFACE_HANDLE InterfaceHandle +); + //KISO_PACKET is equivalent of libusb_iso_packet_descriptor except uses absolute "offset" field instead of sequential Lengths typedef struct _KISO_PACKET { UINT offset; @@ -638,7 +636,7 @@ typedef struct _KISO_CONTEXT { KISO_PACKET IsoPackets[0]; } KISO_CONTEXT, *PKISO_CONTEXT; -typedef BOOL(WINAPI *WinUsb_IsoReadPipe_t)( +typedef BOOL(WINAPI *LibK_IsoReadPipe_t)( WINUSB_INTERFACE_HANDLE InterfaceHandle, UCHAR PipeID, PUCHAR Buffer, @@ -647,7 +645,7 @@ typedef BOOL(WINAPI *WinUsb_IsoReadPipe_t)( PKISO_CONTEXT IsoContext ); -typedef BOOL(WINAPI *WinUsb_IsoWritePipe_t)( +typedef BOOL(WINAPI *LibK_IsoWritePipe_t)( WINUSB_INTERFACE_HANDLE InterfaceHandle, UCHAR PipeID, PUCHAR Buffer, @@ -657,8 +655,7 @@ typedef BOOL(WINAPI *WinUsb_IsoWritePipe_t)( ); struct winusb_interface { - bool initialized; - bool CancelIoEx_supported; + HMODULE hDll; WinUsb_AbortPipe_t AbortPipe; WinUsb_ControlTransfer_t ControlTransfer; WinUsb_FlushPipe_t FlushPipe; @@ -666,22 +663,27 @@ struct winusb_interface { WinUsb_GetAssociatedInterface_t GetAssociatedInterface; WinUsb_Initialize_t Initialize; WinUsb_ReadPipe_t ReadPipe; - WinUsb_ResetDevice_t ResetDevice; WinUsb_ResetPipe_t ResetPipe; WinUsb_SetCurrentAlternateSetting_t SetCurrentAlternateSetting; WinUsb_SetPipePolicy_t SetPipePolicy; WinUsb_WritePipe_t WritePipe; - - // Isochoronous functions for LibUSBk sub api: - WinUsb_IsoReadPipe_t IsoReadPipe; - WinUsb_IsoWritePipe_t IsoWritePipe; - - // Isochronous functions for Microsoft WinUSB sub api (native WinUSB): - WinUsb_RegisterIsochBuffer_t RegisterIsochBuffer; - WinUsb_UnregisterIsochBuffer_t UnregisterIsochBuffer; - WinUsb_WriteIsochPipeAsap_t WriteIsochPipeAsap; - WinUsb_ReadIsochPipeAsap_t ReadIsochPipeAsap; - WinUsb_QueryPipeEx_t QueryPipeEx; + union { + struct { + // Isochoronous functions for libusbK sub api: + LibK_IsoReadPipe_t IsoReadPipe; + LibK_IsoWritePipe_t IsoWritePipe; + // Reset device function for libusbK sub api: + LibK_ResetDevice_t ResetDevice; + }; + struct { + // Isochronous functions for WinUSB sub api: + WinUsb_QueryPipeEx_t QueryPipeEx; + WinUsb_ReadIsochPipeAsap_t ReadIsochPipeAsap; + WinUsb_RegisterIsochBuffer_t RegisterIsochBuffer; + WinUsb_UnregisterIsochBuffer_t UnregisterIsochBuffer; + WinUsb_WriteIsochPipeAsap_t WriteIsochPipeAsap; + }; + }; }; /* hid.dll interface */ diff --git a/libusb/version_nano.h b/libusb/version_nano.h index 7e27bf5..8c3a7c4 100644 --- a/libusb/version_nano.h +++ b/libusb/version_nano.h @@ -1 +1 @@ -#define LIBUSB_NANO 11453 +#define LIBUSB_NANO 11454 |