diff options
author | Pete Batard <pbatard@gmail.com> | 2010-01-14 01:23:19 +0000 |
---|---|---|
committer | Pete Batard <pbatard@gmail.com> | 2010-01-14 01:23:19 +0000 |
commit | 434caf7c49b819f94035643862814a0e86112ec4 (patch) | |
tree | 70278cf7fd9ad4deca05f32e3144c9f2a33ae98a | |
parent | 368130bd31efbb97d709882ded63de870974d3e4 (diff) | |
download | libusb-434caf7c49b819f94035643862814a0e86112ec4.tar.gz |
svn r37:
- windows_set_interface_altsetting (untested)
- windows_set_configuration (untested)
- updated xusb.c test program, with comprehensive XBox Controller test and
preparation for bulk transfers test on Mass Storage device
-rw-r--r-- | examples/xusb.c | 224 | ||||
-rw-r--r-- | libusb/os/windows_usb.c | 99 |
2 files changed, 256 insertions, 67 deletions
diff --git a/examples/xusb.c b/examples/xusb.c index 8614e2f..6ea99f7 100644 --- a/examples/xusb.c +++ b/examples/xusb.c @@ -3,7 +3,7 @@ * based on lsusb, copyright (C) 2007 Daniel Drake <dsd@gentoo.org> * * This test program tries to access an USB device through WinUSB. - * To access your device, change VID/PID. + * To access your device, modify this source and add your VID/PID. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -23,65 +23,111 @@ #include <stdio.h> #include <sys/types.h> #include <inttypes.h> +#include <string.h> +#include "../config.h" #include <libusb/libusb.h> +#ifdef OS_WINDOWS +#include <windows.h> +#define msleep(msecs) Sleep(msecs) +#ifdef interface
+#undef interface
+#endif +#else +#include <unistd.h> +#define msleep(msecs) usleep(1000*msecs) +#endif + #define perr(...) fprintf(stderr, __VA_ARGS__) #define ERR_EXIT(errcode) do { perr(" libusb error: %d\n", errcode); return -1; } while (0) #define CALL_CHECK(fcall) do { r=fcall; if (r < 0) ERR_EXIT(r); } while (0); +#define B(x) (((x)!=0)?1:0) + +// HID Class-Specific Requests values. See section 7.2 of the HID specifications +#define HID_GET_REPORT 0x01 +#define HID_GET_IDLE 0x02 +#define HID_GET_PROTOCOL 0x03 +#define HID_SET_REPORT 0x09 +#define HID_SET_IDLE 0x0A +#define HID_SET_PROTOCOL 0x0B +#define HID_REPORT_TYPE_INPUT 0x01 +#define HID_REPORT_TYPE_OUTPUT 0x02 +#define HID_REPORT_TYPE_FEATURE 0x03 + +// Mass Storage Requests values. See section 3 of the Bulk-Only Mass Storage Class specifications +#define BOMS_RESET 0xFF +#define BOMS_GET_MAX_LUN 0xFE + +enum test_type { + USE_XBOX, + USE_KEY, + USE_JTAG, +} test_mode; +uint16_t VID, PID; + +// The XBOX Controller is really a HID device that got its HID Report Descriptors +// removed by Microsoft. +// Input/Output reports described at http://euc.jp/periphs/xbox-controller.ja.html +int display_xbox_status(libusb_device_handle *handle) +{ + int r; + uint8_t input_report[20]; + printf("Retrieving XBox Input Report...\n"); + CALL_CHECK(libusb_control_transfer(handle, LIBUSB_ENDPOINT_IN|LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE, + HID_GET_REPORT, (HID_REPORT_TYPE_INPUT<<8)|0x00, 0, input_report, 20, 1000)); + printf("D-pad: %02X\n", input_report[2]&0x0F); + printf("Start:%d, Back:%d, Left Stick Press:%d, Right Stick Press:%d\n", B(input_report[2]&0x10), B(input_report[2]&0x20), + B(input_report[2]&0x40), B(input_report[2]&0x80)); + // A, B, X, Y, Black, White are pressure sensitive + printf("A:%d, B:%d, X:%d, Y:%d, White:%d, Black:%d\n", input_report[4], input_report[5], + input_report[6], input_report[7], input_report[9], input_report[8]); + printf("Left Trigger: %d, Right Trigger: %d\n", input_report[10], input_report[11]); + printf("Left Analog (X,Y): (%d,%d)\n", (int16_t)((input_report[13]<<8)|input_report[12]), + (int16_t)((input_report[15]<<8)|input_report[14])); + printf("Right Analog (X,Y): (%d,%d)\n", (int16_t)((input_report[17]<<8)|input_report[16]), + (int16_t)((input_report[19]<<8)|input_report[18])); + return 0; +} -//#define USE_MOUSE -//#define USE_XBOX -#define USE_JTAG - -#ifdef USE_MOUSE -// Logitech optical mouse -#define VID 0x046D -#define PID 0xC03E -#endif +int set_xbox_actuators(libusb_device_handle *handle, uint8_t left, uint8_t right) +{ + int r; + uint8_t output_report[6]; -#ifdef USE_XBOX -// Microsoft XBox Controller -#define VID 0x045E -#define PID 0x0289 -#endif + printf("Writing XBox Controller Output Report...\n"); -#ifdef USE_KEY -// 2 GB Usb key -#define VID 0x0204 -#define PID 0x6025 -#endif + memset(output_report, 0, 6); + output_report[1] = 6; + output_report[3] = left; + output_report[5] = right; -#ifdef USE_JTAG -// OLIMEX ARM-USB-TINY, 2 channel composite device -#define VID 0x15BA -#define PID 0x0004 -#endif + CALL_CHECK(libusb_control_transfer(handle, LIBUSB_ENDPOINT_OUT|LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE, + HID_SET_REPORT, (HID_REPORT_TYPE_OUTPUT<<8)|0x00, 0, output_report, 6, 1000)); + return 0; +} -static void print_devs(libusb_device **devs) +// Mass Storage device to test bulk transfers (/!\ destructive test /!\) +int test_mass_storage(libusb_device_handle *handle) { - libusb_device *dev; - int i = 0; - - while ((dev = devs[i++]) != NULL) { - struct libusb_device_descriptor desc; - int r = libusb_get_device_descriptor(dev, &desc); - if (r < 0) { - perr("failed to get device descriptor\n"); - return; - } - - printf("%04x:%04x (bus %d, device %d)\n", - desc.idVendor, desc.idProduct, - libusb_get_bus_number(dev), libusb_get_device_address(dev)); - } + int r; + unsigned char lun; + 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)); + printf("Getting Max LUN...\n"); + 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); + return 0; } int test_device(uint16_t vid, uint16_t pid) { libusb_device_handle *handle; - int r; - int iface = 1; + libusb_device *dev; + int i, j, r; + int iface = 0; printf("Opening device...\n"); handle = libusb_open_device_with_vid_pid(NULL, vid, pid); @@ -91,6 +137,8 @@ int test_device(uint16_t vid, uint16_t pid) return -1; } + dev = libusb_get_device(handle); + printf("Claiming interface %d...\n", iface); r = libusb_claim_interface(handle, iface); if (r != LIBUSB_SUCCESS) { @@ -101,10 +149,48 @@ int test_device(uint16_t vid, uint16_t pid) CALL_CHECK(libusb_claim_interface(handle, iface)); } - char string[128]; - printf("Retieving string descriptor...\n"); - CALL_CHECK(libusb_get_string_descriptor_ascii(handle, 3, string, 128)); - printf("Got string: \"%s\"\n", string); + struct libusb_device_descriptor dev_desc; + printf("reading device descriptor...\n"); + CALL_CHECK(libusb_get_device_descriptor(dev, &dev_desc)); + printf("length = %d\n", dev_desc.bLength); + printf("device class = %d\n", dev_desc.bDeviceClass); + printf("ser num = %d\n", dev_desc.iSerialNumber); + printf("VID:PID %04X:%04X\n", dev_desc.idVendor, dev_desc.idProduct); + printf("bcdDevice = %04X\n", dev_desc.bcdDevice); + 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); + 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", + i, j, conf_desc->interface[i].altsetting[j].bNumEndpoints); + printf(" Class.SubClass.Protocol: %02X.%02X.%02X\n", + conf_desc->interface[i].altsetting[j].bInterfaceClass, + conf_desc->interface[i].altsetting[j].bInterfaceSubClass, + conf_desc->interface[i].altsetting[j].bInterfaceProtocol); + } + } + libusb_free_config_descriptor(conf_desc); + + if (test_mode == USE_XBOX) { + CALL_CHECK(display_xbox_status(handle)); + CALL_CHECK(set_xbox_actuators(handle, 128, 222)); + msleep(2000); + CALL_CHECK(set_xbox_actuators(handle, 0, 0)); + } else { + char string[128]; + printf("Retieving string descriptor...\n"); + CALL_CHECK(libusb_get_string_descriptor_ascii(handle, 2, string, 128)); + printf("Got string: \"%s\"\n", string); + } + + if (test_mode = USE_KEY) { + CALL_CHECK(test_mass_storage(handle)); + } printf("Releasing interface...\n"); CALL_CHECK(libusb_release_interface(handle, iface)); @@ -115,26 +201,48 @@ int test_device(uint16_t vid, uint16_t pid) return 0; } -int main(void) +int main(int argc, char** argv) { - libusb_device **devs; int r; - ssize_t cnt; + + // Default test = Microsoft XBox Controller Type S + VID = 0x045E; + PID = 0x0289; + test_mode = USE_XBOX; + + if (argc == 2) { + if ((argv[1][0] != '-') || (argv[1][1] == 'h')) { + printf("usage: %s [-h] [-j] [-k] [-x]\n", argv[0]); + printf(" -h: display usage\n"); + printf(" -j: test OLIMEX ARM-USB-TINY JTAG, 2 channel composite device\n"); + printf(" -k: test Generic 2 GB USB Key\n"); + printf(" -x: test Microsoft XBox Controller Type S\n"); + return 0; + } + switch(argv[1][1]) { + case 'j': + // OLIMEX ARM-USB-TINY JTAG, 2 channel composite device + VID = 0x15BA; + PID = 0x0004; + test_mode = USE_JTAG; + break; + case 'k': + // Generic 2 GB USB Key (SCSI Transparent/Bulk Only) + VID = 0x0204; + PID = 0x6025; + test_mode = USE_KEY; + break; + default: + break; + } + } r = libusb_init(NULL); if (r < 0) return r; -/* - cnt = libusb_get_device_list(NULL, &devs); - if (cnt < 0) - return (int) cnt; -*/ -// print_devs(devs); test_device(VID, PID); -// libusb_free_device_list(devs, 1); - libusb_exit(NULL); return 0; } diff --git a/libusb/os/windows_usb.c b/libusb/os/windows_usb.c index a294a96..fc01e59 100644 --- a/libusb/os/windows_usb.c +++ b/libusb/os/windows_usb.c @@ -87,6 +87,7 @@ static void winusb_close(struct libusb_device_handle *dev_handle); static int winusb_claim_interface(struct libusb_device_handle *dev_handle, int iface); 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); // HCD private chained list struct windows_hcd_priv* hcd_root = NULL; @@ -1256,13 +1257,21 @@ static int windows_get_configuration(struct libusb_device_handle *dev_handle, in static int windows_set_configuration(struct libusb_device_handle *dev_handle, int config) { - /* - * 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. - * TODO: See if this is achievable with kernel drivers - */ - return LIBUSB_ERROR_NOT_SUPPORTED; + int r = LIBUSB_SUCCESS; + + if (config >= USB_MAXCONFIG) + return LIBUSB_ERROR_INVALID_PARAM; + + r = libusb_control_transfer(dev_handle, LIBUSB_ENDPOINT_OUT | + LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE, + LIBUSB_REQUEST_SET_CONFIGURATION, config, + 0, NULL, 0, 1000); + + if (r == LIBUSB_SUCCESS) { + // TODO: update pipes data? + } + + return r; } static int windows_claim_interface(struct libusb_device_handle *dev_handle, int iface) @@ -1290,16 +1299,49 @@ static int windows_release_interface(struct libusb_device_handle *dev_handle, in static int windows_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting) { - return LIBUSB_ERROR_NOT_SUPPORTED; + 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); + + return r; } +/* Clear a halt/stall condition on an endpoint. + * + * It's OK for this function to block. + * + * Return: + * - 0 on success + * - LIBUSB_ERROR_NOT_FOUND if the endpoint does not exist + * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it + * was opened + * - another LIBUSB_ERROR code on other failure + */ static int windows_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint) { return LIBUSB_ERROR_NOT_SUPPORTED; } +/* Perform a USB port reset to reinitialize a device. + * + * If possible, the handle should still be usable after the reset + * completes, assuming that the device descriptors did not change during + * reset and all previous interface state can be restored. + * + * If something changes, or you cannot easily locate/verify the resetted + * device, return LIBUSB_ERROR_NOT_FOUND. This prompts the application + * to close the old handle and re-enumerate the device. + * + * Return: + * - 0 on success + * - LIBUSB_ERROR_NOT_FOUND if re-enumeration is required, or if the device + * has been disconnected since it was opened + * - another LIBUSB_ERROR code on other failure + */ static int windows_reset_device(struct libusb_device_handle *dev_handle) { +// http://stackoverflow.com/questions/987958/how-do-i-reset-usb-devices-using-the-windows-api return LIBUSB_ERROR_NOT_SUPPORTED; } @@ -1308,6 +1350,7 @@ static int windows_kernel_driver_active(struct libusb_device_handle *dev_handle, return LIBUSB_ERROR_NOT_SUPPORTED; } +// The 2 functions below are unlikely to ever get supported on Windows static int windows_attach_kernel_driver(struct libusb_device_handle *dev_handle, int iface) { return LIBUSB_ERROR_NOT_SUPPORTED; } @@ -1324,9 +1367,25 @@ 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_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_bulk_transfer, itransfer); + if (r != LIBUSB_SUCCESS) { + return r; + } +
+ usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, POLLIN); + + 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; @@ -1821,7 +1880,29 @@ static int winusb_submit_control_transfer(struct usbi_transfer *itransfer) // Again, use priv_transfer to store data needed for async polling
transfer_priv->pollable_fd = wfd;
- usbi_dbg("overlapped WinUsb_ControlTransfer initiated");
+// usbi_dbg("overlapped WinUsb_ControlTransfer initiated");
+
+ return LIBUSB_SUCCESS;
+}
+
+static int winusb_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting) +{ + struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); + struct windows_device_handle_priv *handle_priv = (struct windows_device_handle_priv *)dev_handle->os_priv; + HANDLE winusb_handle; + + 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"); + return LIBUSB_ERROR_NOT_FOUND; + } + + if (!WinUsb_SetCurrentAlternateSetting(winusb_handle, altsetting)) {
+ usbi_err(ctx, "WinUsb_SetCurrentAlternateSetting failed: %s", windows_error_str(0)); + return LIBUSB_ERROR_IO;
+ }
+
+ usbi_dbg("WinUsb_SetCurrentAlternateSetting success");
return LIBUSB_SUCCESS;
}
|