diff options
author | Pete Batard <pbatard@gmail.com> | 2010-01-14 01:24:28 +0000 |
---|---|---|
committer | Pete Batard <pbatard@gmail.com> | 2010-01-14 01:24:28 +0000 |
commit | 055b0136bf9a59abba662ea1313c516a9b847772 (patch) | |
tree | 14261ed325361c4bb367dddda531db4138764de5 | |
parent | 434caf7c49b819f94035643862814a0e86112ec4 (diff) | |
download | libusb-055b0136bf9a59abba662ea1313c516a9b847772.tar.gz |
svn r38:
- bulk/interrupt I/O at last!
- endpoint handling
- minor code improvements
-rw-r--r-- | examples/xusb.c | 98 | ||||
-rw-r--r-- | libusb/os/windows_usb.c | 244 | ||||
-rw-r--r-- | libusb/os/windows_usb.h | 27 |
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) { |