summaryrefslogtreecommitdiff
path: root/libusb/os/windows_winusb.c
diff options
context:
space:
mode:
Diffstat (limited to 'libusb/os/windows_winusb.c')
-rw-r--r--libusb/os/windows_winusb.c108
1 files changed, 108 insertions, 0 deletions
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,
};
/*