summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPete Batard <pbatard@gmail.com>2010-01-14 01:24:28 +0000
committerPete Batard <pbatard@gmail.com>2010-01-14 01:24:28 +0000
commit055b0136bf9a59abba662ea1313c516a9b847772 (patch)
tree14261ed325361c4bb367dddda531db4138764de5
parent434caf7c49b819f94035643862814a0e86112ec4 (diff)
downloadlibusb-055b0136bf9a59abba662ea1313c516a9b847772.tar.gz
svn r38:
- bulk/interrupt I/O at last! - endpoint handling - minor code improvements
-rw-r--r--examples/xusb.c98
-rw-r--r--libusb/os/windows_usb.c244
-rw-r--r--libusb/os/windows_usb.h27
3 files changed, 287 insertions, 82 deletions
diff --git a/examples/xusb.c b/examples/xusb.c
index 6ea99f7..f641ff8 100644
--- a/examples/xusb.c
+++ b/examples/xusb.c
@@ -59,6 +59,26 @@
#define BOMS_RESET 0xFF
#define BOMS_GET_MAX_LUN 0xFE
+// Section 5.1: Command Block Wrapper (CBW)
+struct command_block_wrapper {
+ uint8_t dCBWSignature[4];
+ uint32_t dCBWTag;
+ uint32_t dCBWDataTransferLength;
+ uint8_t bmCBWFlags;
+ uint8_t bCBWLUN;
+ uint8_t bCBWCBLength;
+ uint8_t CBWCB[16];
+};
+
+// Section 5.2: Command Status Wrapper (CSW)
+struct command_status_wrapper {
+ uint8_t dCSWSignature[4];
+ uint32_t dCSWTag;
+ uint32_t dCSWDataResidue;
+ uint8_t bCSWStatus;
+};
+
+
enum test_type {
USE_XBOX,
USE_KEY,
@@ -110,8 +130,10 @@ int set_xbox_actuators(libusb_device_handle *handle, uint8_t left, uint8_t right
// Mass Storage device to test bulk transfers (/!\ destructive test /!\)
int test_mass_storage(libusb_device_handle *handle)
{
- int r;
+ int r, size;
unsigned char lun;
+ struct command_block_wrapper cbw;
+ struct command_status_wrapper csw;
printf("Sending Mass Storage Reset...\n");
CALL_CHECK(libusb_control_transfer(handle, LIBUSB_ENDPOINT_OUT|LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE,
BOMS_RESET, 0, 0, NULL, 0, 1000));
@@ -119,6 +141,23 @@ int test_mass_storage(libusb_device_handle *handle)
CALL_CHECK(libusb_control_transfer(handle, LIBUSB_ENDPOINT_IN|LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE,
BOMS_GET_MAX_LUN, 0, 0, &lun, 1, 1000));
printf(" Max LUN = %d\n", lun);
+
+ cbw.dCBWSignature[0] = 'U';
+ cbw.dCBWSignature[1] = 'S';
+ cbw.dCBWSignature[2] = 'B';
+ cbw.dCBWSignature[3] = 'C';
+ cbw.dCBWTag = 0x01020304;
+ cbw.dCBWDataTransferLength = 0;
+ cbw.bmCBWFlags = 0;
+ cbw.bCBWLUN = 0;
+ cbw.bCBWCBLength = 1;
+
+ CALL_CHECK(libusb_bulk_transfer(handle, 0x01, (unsigned char*)&cbw, 16, &size, 1000));
+ printf("sent %d bytes\n", size);
+ CALL_CHECK(libusb_bulk_transfer(handle, 0x81, (unsigned char*)&csw, 13, &size, 1000));
+ printf("received %d bytes\n", size);
+ printf("Tag = %08X\n", csw.dCSWTag);
+ printf("Status = %02X\n", csw.bCSWStatus);
return 0;
}
@@ -126,8 +165,10 @@ int test_device(uint16_t vid, uint16_t pid)
{
libusb_device_handle *handle;
libusb_device *dev;
- int i, j, r;
- int iface = 0;
+ struct libusb_config_descriptor *conf_desc;
+ const struct libusb_endpoint_descriptor *endpoint;
+ int i, j, k, r;
+ int iface, nb_ifaces;
printf("Opening device...\n");
handle = libusb_open_device_with_vid_pid(NULL, vid, pid);
@@ -139,16 +180,6 @@ int test_device(uint16_t vid, uint16_t pid)
dev = libusb_get_device(handle);
- printf("Claiming interface %d...\n", iface);
- r = libusb_claim_interface(handle, iface);
- if (r != LIBUSB_SUCCESS) {
- // Maybe we need to detach the driver
- perr("failed. Trying to detach driver...\n");
- CALL_CHECK(libusb_detach_kernel_driver(handle, iface));
- printf("Claiming interface again...\n");
- CALL_CHECK(libusb_claim_interface(handle, iface));
- }
-
struct libusb_device_descriptor dev_desc;
printf("reading device descriptor...\n");
CALL_CHECK(libusb_get_device_descriptor(dev, &dev_desc));
@@ -160,10 +191,10 @@ int test_device(uint16_t vid, uint16_t pid)
printf("iMan:iProd:iSer %d:%d:%d\n", dev_desc.iManufacturer, dev_desc.iProduct, dev_desc.iSerialNumber);
printf("num confs = %d\n", dev_desc.bNumConfigurations);
- struct libusb_config_descriptor *conf_desc;
printf("reading configuration descriptor...\n");
CALL_CHECK(libusb_get_config_descriptor(dev, 0, &conf_desc));
- printf("num interfaces = %d\n", conf_desc->bNumInterfaces);
+ nb_ifaces = conf_desc->bNumInterfaces;
+ printf("num interfaces = %d\n", nb_ifaces);
for (i=0; i<conf_desc->bNumInterfaces; i++) {
for (j=0; j<conf_desc->interface[i].num_altsetting; j++) {
printf("interface[%d].altsetting[%d]: num endpoints = %d\n",
@@ -172,10 +203,33 @@ int test_device(uint16_t vid, uint16_t pid)
conf_desc->interface[i].altsetting[j].bInterfaceClass,
conf_desc->interface[i].altsetting[j].bInterfaceSubClass,
conf_desc->interface[i].altsetting[j].bInterfaceProtocol);
+ for (k=0; k<conf_desc->interface[i].altsetting[j].bNumEndpoints; k++) {
+ endpoint = &conf_desc->interface[i].altsetting[j].endpoint[k];
+ printf(" endpoint[%d].address: %02X\n", k, endpoint->bEndpointAddress);
+ printf(" max packet size: %04X\n", endpoint->wMaxPacketSize);
+ printf(" polling interval: %02X\n", endpoint->bInterval);
+ }
}
}
libusb_free_config_descriptor(conf_desc);
+ for (iface = 0; iface < nb_ifaces; iface++)
+ {
+ printf("Claiming interface %d...\n", iface);
+ r = libusb_claim_interface(handle, iface);
+ if (r != LIBUSB_SUCCESS) {
+ if (iface == 0) {
+ // Maybe we need to detach the driver
+ perr("failed. Trying to detach driver...\n");
+ CALL_CHECK(libusb_detach_kernel_driver(handle, iface));
+ printf("Claiming interface again...\n");
+ CALL_CHECK(libusb_claim_interface(handle, iface));
+ } else {
+ printf("failed.\n");
+ }
+ }
+ }
+
if (test_mode == USE_XBOX) {
CALL_CHECK(display_xbox_status(handle));
CALL_CHECK(set_xbox_actuators(handle, 128, 222));
@@ -188,12 +242,14 @@ int test_device(uint16_t vid, uint16_t pid)
printf("Got string: \"%s\"\n", string);
}
- if (test_mode = USE_KEY) {
+ if (test_mode == USE_KEY) {
CALL_CHECK(test_mass_storage(handle));
}
- printf("Releasing interface...\n");
- CALL_CHECK(libusb_release_interface(handle, iface));
+ for (iface = 0; iface<nb_ifaces; iface++) {
+ printf("Releasing interface %d...\n", iface);
+ libusb_release_interface(handle, iface);
+ }
printf("Closing device...\n");
libusb_close(handle);
@@ -205,7 +261,7 @@ int main(int argc, char** argv)
{
int r;
- // Default test = Microsoft XBox Controller Type S
+ // Default test = Microsoft XBox Controller Type S - 1 interface
VID = 0x045E;
PID = 0x0289;
test_mode = USE_XBOX;
@@ -221,13 +277,13 @@ int main(int argc, char** argv)
}
switch(argv[1][1]) {
case 'j':
- // OLIMEX ARM-USB-TINY JTAG, 2 channel composite device
+ // OLIMEX ARM-USB-TINY JTAG, 2 channel composite device - 2 interfaces
VID = 0x15BA;
PID = 0x0004;
test_mode = USE_JTAG;
break;
case 'k':
- // Generic 2 GB USB Key (SCSI Transparent/Bulk Only)
+ // Generic 2 GB USB Key (SCSI Transparent/Bulk Only) - 1 interface
VID = 0x0204;
PID = 0x6025;
test_mode = USE_KEY;
diff --git a/libusb/os/windows_usb.c b/libusb/os/windows_usb.c
index fc01e59..18885f8 100644
--- a/libusb/os/windows_usb.c
+++ b/libusb/os/windows_usb.c
@@ -88,6 +88,8 @@ static int winusb_claim_interface(struct libusb_device_handle *dev_handle, int i
static int winusb_release_interface(struct libusb_device_handle *dev_handle, int iface);
static int winusb_submit_control_transfer(struct usbi_transfer *itransfer);
static int winusb_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting);
+static int winusb_submit_bulk_transfer(struct usbi_transfer *itransfer);
+static int winusb_submit_iso_transfer(struct usbi_transfer *itransfer);
// HCD private chained list
struct windows_hcd_priv* hcd_root = NULL;
@@ -267,6 +269,54 @@ err_exit:
return NULL;
}
+/*
+ * Populate the endpoints addresses of the device_priv interface helper structs
+ */
+static void windows_assign_endpoints(struct libusb_device *dev, int iface, int altsetting)
+{
+ int i;
+ struct windows_device_priv *priv = __device_priv(dev);
+ struct libusb_config_descriptor *conf_desc;
+ const struct libusb_interface_descriptor *if_desc;
+
+ if (libusb_get_config_descriptor(dev, 0, &conf_desc) == LIBUSB_SUCCESS) {
+ if_desc = &conf_desc->interface[iface].altsetting[altsetting];
+ safe_free(priv->interface[iface].endpoint);
+ priv->interface[iface].endpoint = malloc(if_desc->bNumEndpoints);
+ if (priv->interface[iface].endpoint != NULL) {
+ priv->interface[iface].nb_endpoints = if_desc->bNumEndpoints;
+ for (i=0; i<if_desc->bNumEndpoints; i++) {
+ priv->interface[iface].endpoint[i] = if_desc->endpoint[i].bEndpointAddress;
+ usbi_dbg("assigned endpoint %02X to interface %d", priv->interface[iface].endpoint[i], iface);
+ }
+ }
+ libusb_free_config_descriptor(conf_desc);
+ }
+}
+
+/*
+ * Lookup interface by endpoint address. -1 if not found
+ */
+static int interface_by_endpoint(struct windows_device_priv *priv,
+ struct windows_device_handle_priv *handle_priv, uint8_t endpoint_address)
+{
+ int i, j;
+ for (i=0; i<USB_MAXINTERFACES; i++) {
+ if (handle_priv->interface_handle[i].winusb == INVALID_HANDLE_VALUE)
+ continue;
+ if (handle_priv->interface_handle[i].winusb == 0)
+ continue;
+ if (priv->interface[i].endpoint == NULL)
+ continue;
+ for (j=0; j<priv->interface[i].nb_endpoints; j++) {
+ if (priv->interface[i].endpoint[j] == endpoint_address) {
+ return i;
+ }
+ }
+ }
+ return -1;
+}
+
/*
* init: libusb backend init function
*
@@ -335,23 +385,6 @@ static int windows_init(struct libusb_context *ctx)
usbi_dbg("hires timer available (Frequency: %"PRIu64" Hz)", hires_frequency);
}
-//#define TEST_TIMER 3333
-#ifdef TEST_TIMER
- // Test our timer
- struct timespec tp;
- uint64_t start_time, end_time;
- uint64_t duration_ms = TEST_TIMER;
- if (windows_clock_gettime(USBI_CLOCK_MONOTONIC, &tp) != LIBUSB_SUCCESS)
- return LIBUSB_ERROR_OTHER;
- // Make sure computations are 64 bit
- start_time = ((uint64_t)tp.tv_sec)*1000000000 + ((uint64_t)tp.tv_nsec);
- Sleep(duration_ms);
- if (windows_clock_gettime(USBI_CLOCK_MONOTONIC, &tp) != LIBUSB_SUCCESS)
- return LIBUSB_ERROR_OTHER;
- end_time = ((uint64_t)tp.tv_sec)*1000000000 + ((uint64_t)tp.tv_nsec);
- usbi_dbg("timed %"PRIu64" ns: %"PRIu64" ns", (uint64_t)(duration_ms*1000000), (uint64_t)(end_time-start_time));
-#endif
-
// We maintain a chained list of the Host Controllers found
struct windows_hcd_priv** _hcd_cur = &hcd_root;
@@ -512,7 +545,7 @@ static int cache_config_descriptors(struct libusb_device *dev, HANDLE hub_handle
memset(&cd_buf_short, 0, size);
cd_buf_short.req.ConnectionIndex = priv->connection_index;
- cd_buf_short.req.SetupPacket.bmRequest = 0x80;
+ cd_buf_short.req.SetupPacket.bmRequest = LIBUSB_ENDPOINT_IN;
cd_buf_short.req.SetupPacket.bRequest = USB_REQUEST_GET_DESCRIPTOR;
cd_buf_short.req.SetupPacket.wValue = (USB_CONFIGURATION_DESCRIPTOR_TYPE << 8) | i;
cd_buf_short.req.SetupPacket.wIndex = i;
@@ -539,7 +572,7 @@ static int cache_config_descriptors(struct libusb_device *dev, HANDLE hub_handle
// Actual call
cd_buf_actual->ConnectionIndex = priv->connection_index;
- cd_buf_actual->SetupPacket.bmRequest = 0x80;
+ cd_buf_actual->SetupPacket.bmRequest = LIBUSB_ENDPOINT_IN;
cd_buf_actual->SetupPacket.bRequest = USB_REQUEST_GET_DESCRIPTOR;
cd_buf_actual->SetupPacket.wValue = (USB_CONFIGURATION_DESCRIPTOR_TYPE << 8) | i;
cd_buf_actual->SetupPacket.wIndex = i;
@@ -920,18 +953,18 @@ static int set_composite_device(struct libusb_context *ctx, DEVINST devinst, str
for (j=0; j<nb_paths; j++) {
if (safe_strncmp(sanitized_path[j], sanitized_short, strlen(sanitized_short)) == 0) {
- priv->interface_path[interface_number] = sanitized_path[j];
+ priv->interface[interface_number].path = sanitized_path[j];
sanitized_path[j] = NULL;
}
}
safe_free(sanitized_short);
- if (priv->interface_path[interface_number] == NULL) {
+ if (priv->interface[interface_number].path == NULL) {
usbi_warn(ctx, "could not retrieve full path for interface %d",
interface_number);
continue;
}
- usbi_dbg("interface_path[%d]: %s", interface_number, priv->interface_path[interface_number]);
+ usbi_dbg("interface_path[%d]: %s", interface_number, priv->interface[interface_number].path);
found = true;
}
@@ -1009,6 +1042,7 @@ static int set_device_paths(struct libusb_context *ctx, struct discovered_devs *
// We're out of luck for Location Information on XP, since SPDRP_LOCATION_INFORMATION
// returns anything but an actual location. However, it looks like the port number is
// the last digit before '#{' in the path string, so let's try that.
+ // TODO: device enum that doesn't require this workaround
found = false;
for (j=0; j<safe_strlen(dev_interface_details->DevicePath); j++) {
if ( (dev_interface_details->DevicePath[j] == '{')
@@ -1087,7 +1121,7 @@ static int set_device_paths(struct libusb_context *ctx, struct discovered_devs *
if (safe_strcmp(priv->driver, "WinUSB") == 0) {
priv->api = API_WINUSB;
// For non composite, the first interface is the same as the device
- priv->interface_path[0] = safe_strdup(priv->path); // needs strdup
+ priv->interface[0].path = safe_strdup(priv->path); // needs strdup
// Composite (multi-interface) devices are identified by their use of
// the USB Common Class Generic Parent driver
} else if (safe_strcmp(reg_key, "usbccgp") == 0) {
@@ -1225,7 +1259,6 @@ static int windows_open(struct libusb_device_handle *dev_handle)
API_CALL(priv->api, open, dev_handle);
- // TODO: update pipe info here?
return r;
}
@@ -1240,8 +1273,6 @@ static void windows_close(struct libusb_device_handle *dev_handle)
default:
break;
}
-
- // TODO: free pipe?
}
/*
@@ -1255,6 +1286,13 @@ static int windows_get_configuration(struct libusb_device_handle *dev_handle, in
return LIBUSB_SUCCESS;
}
+/*
+ * from http://msdn.microsoft.com/en-us/library/ms793522.aspx: The port driver
+ * does not currently expose a service that allows higher-level drivers to set
+ * the configuration.
+ * The current version of this function still attempts to change conf to see
+ * what happens...
+ */
static int windows_set_configuration(struct libusb_device_handle *dev_handle, int config)
{
int r = LIBUSB_SUCCESS;
@@ -1268,7 +1306,7 @@ static int windows_set_configuration(struct libusb_device_handle *dev_handle, in
0, NULL, 0, 1000);
if (r == LIBUSB_SUCCESS) {
- // TODO: update pipes data?
+ // If the above ever works, you'd need to invalidate the endpoints & interfaces
}
return r;
@@ -1282,27 +1320,42 @@ static int windows_claim_interface(struct libusb_device_handle *dev_handle, int
if (iface >= USB_MAXINTERFACES)
return LIBUSB_ERROR_INVALID_PARAM;
+ safe_free(priv->interface[iface].endpoint);
+ priv->interface[iface].nb_endpoints= 0;
+
API_CALL(priv->api, claim_interface, dev_handle, iface);
+ if (r == LIBUSB_SUCCESS) {
+ windows_assign_endpoints(dev_handle->dev, iface, 0);
+ }
+
return r;
}
-static int windows_release_interface(struct libusb_device_handle *dev_handle, int iface)
+static int windows_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting)
{
int r = LIBUSB_SUCCESS;
struct windows_device_priv *priv = __device_priv(dev_handle->dev);
- API_CALL(priv->api, release_interface, dev_handle, iface);
+ safe_free(priv->interface[iface].endpoint);
+ priv->interface[iface].nb_endpoints= 0;
+
+ API_CALL(priv->api, set_interface_altsetting, dev_handle, iface, altsetting);
+
+ if (r == LIBUSB_SUCCESS) {
+ windows_assign_endpoints(dev_handle->dev, iface, altsetting);
+ }
return r;
}
-static int windows_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting)
+static int windows_release_interface(struct libusb_device_handle *dev_handle, int iface)
{
int r = LIBUSB_SUCCESS;
struct windows_device_priv *priv = __device_priv(dev_handle->dev);
- API_CALL(priv->api, set_interface_altsetting, dev_handle, iface, altsetting);
+ windows_set_interface_altsetting(dev_handle, iface, 0);
+ API_CALL(priv->api, release_interface, dev_handle, iface);
return r;
}
@@ -1367,7 +1420,7 @@ static void windows_destroy_device(struct libusb_device *dev)
static int submit_bulk_transfer(struct usbi_transfer *itransfer)
{
-/* struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
struct windows_device_priv *priv = __device_priv(transfer->dev_handle->dev);
@@ -1378,17 +1431,30 @@ static int submit_bulk_transfer(struct usbi_transfer *itransfer)
return r;
}
- usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, POLLIN);
+ usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd,
+ (transfer->endpoint & LIBUSB_ENDPOINT_IN)?POLLIN:POLLOUT);
return LIBUSB_SUCCESS;
-*/
- return LIBUSB_ERROR_NOT_SUPPORTED;
}
// WinUSB does not support isochronous transfers
static int submit_iso_transfer(struct usbi_transfer *itransfer)
{
- return LIBUSB_ERROR_NOT_SUPPORTED;
+ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
+ struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
+ struct windows_device_priv *priv = __device_priv(transfer->dev_handle->dev);
+ int r;
+
+ API_CALL(priv->api, submit_iso_transfer, itransfer);
+ if (r != LIBUSB_SUCCESS) {
+ return r;
+ }
+
+ usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd,
+ (transfer->endpoint & LIBUSB_ENDPOINT_IN)?POLLIN:POLLOUT);
+
+ return LIBUSB_SUCCESS;
}
static int submit_control_transfer(struct usbi_transfer *itransfer)
@@ -1457,6 +1523,7 @@ static int windows_cancel_transfer(struct usbi_transfer *itransfer)
static void windows_clear_transfer_priv(struct usbi_transfer *itransfer)
{
+ // TODO
}
static void windows_control_callback (struct usbi_transfer *itransfer, uint32_t io_result, uint32_t io_size)
@@ -1483,6 +1550,29 @@ static void windows_control_callback (struct usbi_transfer *itransfer, uint32_t
usbi_handle_transfer_completion(itransfer, status);
}
+static void windows_bulk_callback (struct usbi_transfer *itransfer, uint32_t io_result, uint32_t io_size)
+{
+ int status;
+
+ usbi_dbg("handling I/O completion with status %d", io_result);
+
+ switch(io_result) {
+ case NO_ERROR:
+ status = LIBUSB_TRANSFER_COMPLETED;
+ itransfer->transferred += io_size;
+ break;
+ case ERROR_GEN_FAILURE:
+ usbi_dbg("unsupported I/O request");
+ status = LIBUSB_TRANSFER_STALL;
+ break;
+ default:
+ usbi_err(ITRANSFER_CTX(itransfer), "I/O error: %s", windows_error_str(0));
+ status = LIBUSB_TRANSFER_ERROR;
+ break;
+ }
+
+ usbi_handle_transfer_completion(itransfer, status);
+}
static void windows_handle_callback (struct usbi_transfer *itransfer, uint32_t io_result, uint32_t io_size)
{
@@ -1494,7 +1584,7 @@ static void windows_handle_callback (struct usbi_transfer *itransfer, uint32_t i
break;
case LIBUSB_TRANSFER_TYPE_BULK:
case LIBUSB_TRANSFER_TYPE_INTERRUPT:
-// windows_bulk_callback (itransfer, io_result, io_size);
+ windows_bulk_callback (itransfer, io_result, io_size);
break;
case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
// TODO: ain't gonna happen with WinUSB only
@@ -1635,7 +1725,6 @@ const struct usbi_os_backend windows_backend = {
* WinUSB API functions
*/
-// TO_DO: check if DLL has been loaded in all functions?
static int winusb_api_init(struct libusb_context *ctx)
{
DLL_LOAD(winusb.dll, WinUsb_Initialize, TRUE);
@@ -1666,9 +1755,6 @@ static int winusb_api_exit(void)
return LIBUSB_SUCCESS;
}
-/*
- * TODO: check if device has been diconnected
- */
static int winusb_open(struct libusb_device_handle *dev_handle)
{
struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
@@ -1680,12 +1766,10 @@ static int winusb_open(struct libusb_device_handle *dev_handle)
CHECK_WINUSB_AVAILABLE;
- // TODO: better check for detached devices
-
// Each interface requires a sperate handle for WinUSB
for (i = 0; i < USB_MAXINTERFACES; i++) {
- if (priv->interface_path[i] != NULL) {
- file_handle = CreateFileA(priv->interface_path[i], GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ,
+ if (priv->interface[i].path != NULL) {
+ file_handle = CreateFileA(priv->interface[i].path, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
if (file_handle == INVALID_HANDLE_VALUE) {
usbi_err(ctx, "could not open device %s (interface %d): %s", priv->path, i, windows_error_str(0));
@@ -1802,12 +1886,6 @@ static int winusb_claim_interface(struct libusb_device_handle *dev_handle, int i
return LIBUSB_SUCCESS;
}
-/*
- * TODO:
- * This function should also generate a SET_INTERFACE control request,
- * resetting the alternate setting of that interface to 0. It's OK for
- * this function to block as a result.
- */
static int winusb_release_interface(struct libusb_device_handle *dev_handle, int iface)
{
struct windows_device_handle_priv *handle_priv = (struct windows_device_handle_priv *)dev_handle->os_priv;
@@ -1862,7 +1940,7 @@ static int winusb_submit_control_transfer(struct usbi_transfer *itransfer)
// usbi_dbg("active interface = %d (handle = %p)", handle_priv->active_interface, handle_priv->interface_handle[handle_priv->active_interface].winusb);
wfd = create_fd_for_poll(winusb_handle, _O_RDONLY);
if (wfd.fd < 0) {
- return LIBUSB_ERROR_NO_MEM; // somtehing else
+ return LIBUSB_ERROR_NO_MEM;
}
if (!WinUsb_ControlTransfer(wfd.handle, *setup, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, size, NULL, wfd.overlapped)) {
@@ -1891,6 +1969,8 @@ static int winusb_set_interface_altsetting(struct libusb_device_handle *dev_hand
struct windows_device_handle_priv *handle_priv = (struct windows_device_handle_priv *)dev_handle->os_priv;
HANDLE winusb_handle;
+ CHECK_WINUSB_AVAILABLE;
+
winusb_handle = handle_priv->interface_handle[iface].winusb;
if ((winusb_handle == 0) || (winusb_handle == INVALID_HANDLE_VALUE)) {
usbi_err(ctx, "interface must be claimed first");
@@ -1906,3 +1986,63 @@ static int winusb_set_interface_altsetting(struct libusb_device_handle *dev_hand
return LIBUSB_SUCCESS;
}
+
+static int winusb_submit_bulk_transfer(struct usbi_transfer *itransfer)
+{
+ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
+ struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
+ struct windows_device_handle_priv *handle_priv = (struct windows_device_handle_priv *)transfer->dev_handle->os_priv;
+ struct windows_device_priv *priv = __device_priv(transfer->dev_handle->dev);
+ HANDLE winusb_handle;
+ bool direction_in, ret;
+ int current_interface = -1;
+ struct winfd wfd;
+
+ CHECK_WINUSB_AVAILABLE;
+
+ transfer_priv->pollable_fd = INVALID_WINFD;
+
+ current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint);
+ if (current_interface < 0) {
+ usbi_err(ctx, "unable to match endpoint to an open interface - cancelling transfer");
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ usbi_dbg("matched endpoint %02X with interface %d", transfer->endpoint, current_interface);
+
+ winusb_handle = handle_priv->interface_handle[current_interface].winusb;
+ direction_in = transfer->endpoint & LIBUSB_ENDPOINT_IN;
+
+ wfd = create_fd_for_poll(winusb_handle, direction_in?_O_RDONLY:_O_WRONLY);
+ if (wfd.fd < 0) {
+ return LIBUSB_ERROR_NO_MEM;
+ }
+
+ if (direction_in) {
+ usbi_dbg("reading %d bytes", transfer->length);
+ ret = WinUsb_ReadPipe(winusb_handle, transfer->endpoint, transfer->buffer, transfer->length, NULL, wfd.overlapped);
+ } else {
+ usbi_dbg("writing %d bytes", transfer->length);
+ ret = WinUsb_WritePipe(winusb_handle, transfer->endpoint, transfer->buffer, transfer->length, NULL, wfd.overlapped);
+ }
+ if (!ret) {
+ if(GetLastError() != ERROR_IO_PENDING) {
+ usbi_err(ctx, "WinUsb_Pipe Transfer failed: %s", windows_error_str(0));
+ free_fd_for_poll(wfd.fd);
+ return LIBUSB_ERROR_IO;
+ }
+ } else {
+ usbi_err(ctx, "chill out man; this is like way too fast for async I/O...");
+ free_fd_for_poll(wfd.fd);
+ return LIBUSB_ERROR_IO;
+ }
+
+ transfer_priv->pollable_fd = wfd;
+
+ return LIBUSB_SUCCESS;
+}
+
+static int winusb_submit_iso_transfer(struct usbi_transfer *itransfer) {
+ return LIBUSB_ERROR_NOT_SUPPORTED;
+}
diff --git a/libusb/os/windows_usb.h b/libusb/os/windows_usb.h
index c2d9c7f..fdde21e 100644
--- a/libusb/os/windows_usb.h
+++ b/libusb/os/windows_usb.h
@@ -121,14 +121,18 @@ static inline void windows_hcd_priv_release(struct windows_hcd_priv* p) {
// Nodes (Hubs & devices)
struct windows_device_priv {
struct libusb_device *parent_dev; // access to parent is required for usermode ops
- ULONG connection_index; // also required for some usermode ops
- char *path; // path used by Windows to reference the USB node
- char *interface_path[USB_MAXINTERFACES]; // each interface has a path as well
- char *driver; // driver name (eg WinUSB, USBSTOR, HidUsb, etc)
+ ULONG connection_index; // also required for some usermode ops
+ char *path; // path used by Windows to reference the USB node
+ struct {
+ char *path; // each interface has a path as well
+ int8_t nb_endpoints; // and a set of endpoint addresses (USB_MAXENDPOINTS)
+ uint8_t *endpoint;
+ } interface[USB_MAXINTERFACES];
+ char *driver; // driver name (eg WinUSB, USBSTOR, HidUsb, etc)
enum api_type api;
uint8_t active_config;
USB_DEVICE_DESCRIPTOR dev_descriptor;
- unsigned char **config_descriptor; // list of pointers to the cached config descriptors
+ unsigned char **config_descriptor; // list of pointers to the cached config descriptors
};
static inline void windows_device_priv_init(struct windows_device_priv* p) {
@@ -141,8 +145,11 @@ static inline void windows_device_priv_init(struct windows_device_priv* p) {
p->active_config = 0;
p->config_descriptor = NULL;
memset(&(p->dev_descriptor), 0, sizeof(USB_DEVICE_DESCRIPTOR));
- for (i=0; i<USB_MAXINTERFACES; i++)
- p->interface_path[i] = NULL;
+ for (i=0; i<USB_MAXINTERFACES; i++) {
+ p->interface[i].path = NULL;
+ p->interface[i].nb_endpoints = 0;
+ p->interface[i].endpoint = NULL;
+ }
}
static inline void windows_device_priv_release(struct windows_device_priv* p, int num_configurations) {
@@ -154,8 +161,10 @@ static inline void windows_device_priv_release(struct windows_device_priv* p, in
safe_free(p->config_descriptor[i]);
}
safe_free(p->config_descriptor);
- for (i=0; i<USB_MAXINTERFACES; i++)
- safe_free(p->interface_path[i]);
+ for (i=0; i<USB_MAXINTERFACES; i++) {
+ safe_free(p->interface[i].path);
+ safe_free(p->interface[i].endpoint);
+ }
}
static inline struct windows_device_priv *__device_priv(struct libusb_device *dev) {