summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libusb/core.c1
-rw-r--r--libusb/libusb.h35
-rw-r--r--libusb/os/windows_common.c6
-rw-r--r--libusb/os/windows_common.h1
-rw-r--r--libusb/os/windows_usbdk.c1
-rw-r--r--libusb/os/windows_winusb.c108
-rw-r--r--libusb/version_nano.h2
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