diff options
-rw-r--r-- | libusb/core.c | 1 | ||||
-rw-r--r-- | libusb/libusb.h | 35 | ||||
-rw-r--r-- | libusb/os/windows_common.c | 6 | ||||
-rw-r--r-- | libusb/os/windows_common.h | 1 | ||||
-rw-r--r-- | libusb/os/windows_usbdk.c | 1 | ||||
-rw-r--r-- | libusb/os/windows_winusb.c | 108 | ||||
-rw-r--r-- | libusb/version_nano.h | 2 |
7 files changed, 150 insertions, 4 deletions
diff --git a/libusb/core.c b/libusb/core.c index 497c7f6..e43e47c 100644 --- a/libusb/core.c +++ b/libusb/core.c @@ -2233,6 +2233,7 @@ int API_EXPORTEDV libusb_set_option(libusb_context *ctx, /* Handle all backend-specific options here */ case LIBUSB_OPTION_USE_USBDK: case LIBUSB_OPTION_NO_DEVICE_DISCOVERY: + case LIBUSB_OPTION_WINUSB_RAW_IO: if (usbi_backend.set_option) return usbi_backend.set_option(ctx, option, ap); diff --git a/libusb/libusb.h b/libusb/libusb.h index a865bc8..ed54d91 100644 --- a/libusb/libusb.h +++ b/libusb/libusb.h @@ -1501,7 +1501,40 @@ enum libusb_option { #define LIBUSB_OPTION_WEAK_AUTHORITY LIBUSB_OPTION_NO_DEVICE_DISCOVERY - LIBUSB_OPTION_MAX = 3 + /** Enable or disable WinUSB RAW_IO mode on an endpoint + * + * Requires four additional arguments of: + * + * libusb_device_handle *dev_handle + * unsigned int endpoint_address + * unsigned int enable + * unsigned int *max_transfer_size_ptr + * + * The dev_handle and endpoint_address parameters must identify a valid + * IN endpoint on an open device. If enable is nonzero, RAW_IO is + * enabled, otherwise it is disabled. Unless max_transfer_size_ptr is + * NULL, then on a successful call to enable RAW_IO, it will be written + * with the MAXIMUM_TRANSFER_SIZE value for the endpoint. + * + * Whilst RAW_IO is enabled for an endpoint, all transfers on that endpoint + * must meet the following two requirements: + * + * * The buffer length must be a multiple of the maximum endpoint packet size. + * + * * The length must be less than or equal to the MAXIMUM_TRANSFER_SIZE value. + * + * This option should not be changed when any transfer is in progress on the + * specified endpoint. + * + * This option only affects the WinUSB backend. On other backends it is ignored + * and returns LIBUSB_OPTION_NOT_SUPPORTED, without modifying the value pointed + * to by max_transfer_size_ptr. + * + * Since version 1.0.27, \ref LIBUSB_API_VERSION >= 0x0100010A + */ + LIBUSB_OPTION_WINUSB_RAW_IO = 3, + + LIBUSB_OPTION_MAX = 4 }; /** \ingroup libusb_lib diff --git a/libusb/os/windows_common.c b/libusb/os/windows_common.c index 32887fb..308bbc8 100644 --- a/libusb/os/windows_common.c +++ b/libusb/os/windows_common.c @@ -607,8 +607,6 @@ static int windows_set_option(struct libusb_context *ctx, enum libusb_option opt { struct windows_context_priv *priv = usbi_get_context_priv(ctx); - UNUSED(ap); - if (option == LIBUSB_OPTION_USE_USBDK) { if (!usbdk_available) { usbi_err(ctx, "UsbDk backend not available"); @@ -619,6 +617,10 @@ static int windows_set_option(struct libusb_context *ctx, enum libusb_option opt return LIBUSB_SUCCESS; } + if (priv->backend->set_option) { + return priv->backend->set_option(ctx, option, ap); + } + return LIBUSB_ERROR_NOT_SUPPORTED; } diff --git a/libusb/os/windows_common.h b/libusb/os/windows_common.h index ff0a5b7..49c02ab 100644 --- a/libusb/os/windows_common.h +++ b/libusb/os/windows_common.h @@ -341,6 +341,7 @@ struct windows_backend { int (*cancel_transfer)(struct usbi_transfer *itransfer); void (*clear_transfer_priv)(struct usbi_transfer *itransfer); enum libusb_transfer_status (*copy_transfer_data)(struct usbi_transfer *itransfer, DWORD length); + int (*set_option)(struct libusb_context *ctx, enum libusb_option option, va_list args); }; struct windows_context_priv { diff --git a/libusb/os/windows_usbdk.c b/libusb/os/windows_usbdk.c index 9f52b48..4c08bcf 100644 --- a/libusb/os/windows_usbdk.c +++ b/libusb/os/windows_usbdk.c @@ -721,4 +721,5 @@ const struct windows_backend usbdk_backend = { NULL, /* cancel_transfer */ usbdk_clear_transfer_priv, usbdk_copy_transfer_data, + NULL /* usbdk_set_option */, }; diff --git a/libusb/os/windows_winusb.c b/libusb/os/windows_winusb.c index 4100eaa..99635f2 100644 --- a/libusb/os/windows_winusb.c +++ b/libusb/os/windows_winusb.c @@ -42,6 +42,8 @@ continue; \ } +static int interface_by_endpoint(struct winusb_device_priv *priv, + struct winusb_device_handle_priv *handle_priv, uint8_t endpoint_address); // WinUSB-like API prototypes static bool winusbx_init(struct libusb_context *ctx); static void winusbx_exit(void); @@ -2167,6 +2169,111 @@ static enum libusb_transfer_status winusb_copy_transfer_data(struct usbi_transfe return priv->apib->copy_transfer_data(SUB_API_NOTSET, itransfer, length); } +static int winusb_set_option(struct libusb_context *ctx, enum libusb_option option, va_list ap) +{ + struct libusb_device_handle *dev_handle; + unsigned int endpoint; + unsigned int enable; + unsigned int *max_transfer_size_ptr; + struct winusb_device_handle_priv *handle_priv; + struct winusb_device_priv *priv; + UCHAR policy; + int current_interface; + HANDLE winusb_handle; + int sub_api = SUB_API_NOTSET; + ULONG max_transfer_size = 0; + + switch (option) { + case LIBUSB_OPTION_WINUSB_RAW_IO: + dev_handle = va_arg(ap, struct libusb_device_handle *); + endpoint = va_arg(ap, unsigned int); + enable = va_arg(ap, unsigned int); + max_transfer_size_ptr = va_arg(ap, unsigned int *); + + policy = enable != 0; + + if (dev_handle == NULL) { + usbi_err(ctx, "device handle passed for RAW_IO was NULL"); + return LIBUSB_ERROR_INVALID_PARAM; + } + + if (HANDLE_CTX(dev_handle) != ctx) { + usbi_err(ctx, "device handle passed for RAW_IO has wrong context"); + return LIBUSB_ERROR_INVALID_PARAM; + } + + if (endpoint & ~(LIBUSB_ENDPOINT_DIR_MASK | LIBUSB_ENDPOINT_ADDRESS_MASK)) { + usbi_err(ctx, "invalid endpoint %X passed for RAW_IO", endpoint); + return LIBUSB_ERROR_INVALID_PARAM; + } + + if (!(endpoint & LIBUSB_ENDPOINT_DIR_MASK)) { + usbi_err(ctx, "endpoint %02X passed for RAW_IO is OUT, not IN", endpoint); + return LIBUSB_ERROR_INVALID_PARAM; + } + + handle_priv = get_winusb_device_handle_priv(dev_handle); + priv = usbi_get_device_priv(dev_handle->dev); + current_interface = interface_by_endpoint(priv, handle_priv, (uint8_t) endpoint); + + if (current_interface < 0) { + usbi_err(ctx, "unable to match endpoint to an open interface for RAW_IO"); + return LIBUSB_ERROR_NOT_FOUND; + } + + if (priv->usb_interface[current_interface].apib->id != USB_API_WINUSBX) { + usbi_err(ctx, "interface is not winusb when setting RAW_IO"); + return LIBUSB_ERROR_NOT_SUPPORTED; + } + + winusb_handle = handle_priv->interface_handle[current_interface].api_handle; + + if (!HANDLE_VALID(winusb_handle)) { + usbi_err(HANDLE_CTX(dev_handle), "WinUSB handle not valid when setting RAW_IO"); + return LIBUSB_ERROR_NOT_FOUND; + } + + CHECK_WINUSBX_AVAILABLE(sub_api); + + if (enable && max_transfer_size_ptr != NULL) { + ULONG size = sizeof(ULONG); + if (!WinUSBX[sub_api].GetPipePolicy(winusb_handle, (UCHAR) endpoint, + MAXIMUM_TRANSFER_SIZE, &size, &max_transfer_size)) { + usbi_err(ctx, "failed to get MAXIMUM_TRANSFER_SIZE for endpoint %02X", endpoint); + switch (GetLastError()) { + case ERROR_INVALID_HANDLE: + return LIBUSB_ERROR_INVALID_PARAM; + default: + return LIBUSB_ERROR_OTHER; + } + } + } + + if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, (UCHAR) endpoint, + RAW_IO, sizeof(UCHAR), &policy)) { + usbi_err(ctx, "failed to change RAW_IO for endpoint %02X", endpoint); + switch (GetLastError()) { + case ERROR_INVALID_HANDLE: + case ERROR_INVALID_PARAMETER: + return LIBUSB_ERROR_INVALID_PARAM; + case ERROR_NOT_ENOUGH_MEMORY: + return LIBUSB_ERROR_NO_MEM; + default: + return LIBUSB_ERROR_OTHER; + } + } + + usbi_dbg(ctx, "%s RAW_IO for endpoint %02X", enable ? "enabled" : "disabled", endpoint); + + if (enable && max_transfer_size_ptr != NULL) + *max_transfer_size_ptr = max_transfer_size; + + return LIBUSB_SUCCESS; + default: + return LIBUSB_ERROR_NOT_SUPPORTED; + } +} + // NB: MSVC6 does not support named initializers. const struct windows_backend winusb_backend = { winusb_init, @@ -2189,6 +2296,7 @@ const struct windows_backend winusb_backend = { winusb_cancel_transfer, winusb_clear_transfer_priv, winusb_copy_transfer_data, + winusb_set_option, }; /* diff --git a/libusb/version_nano.h b/libusb/version_nano.h index ade020c..1874d60 100644 --- a/libusb/version_nano.h +++ b/libusb/version_nano.h @@ -1 +1 @@ -#define LIBUSB_NANO 11770 +#define LIBUSB_NANO 11771 |