/* * Copyright (C) 2006 Eric Biederman (ebiederm@xmission.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 as published by the Free Software Foundation. * * gcc -Wall -o ./usbtest ./usbtest.c -lusb */ #include #include #include #include #include #define DEBUG_DEVICE_MAX 8 #ifndef USB_DT_DEBUG #define USB_DT_DEBUG 10 #endif #ifndef USB_FT_DEBUG_MODE #define USB_FT_DEBUG_MODE 6 #endif #define CTRL_TIMEOUT (5*1000) /* milliseconds */ #define WRITE_TIMEOUT (60*1000*1000) /* 1 minute */ struct usb_debug_descriptor { uint8_t bLength; uint8_t bDescriptorType; uint8_t bDebugInEndpoint; uint8_t bDebugOutEndpoint; } __attribute__ ((packed)); static void die(char *fmt, ...) { va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); fflush(stderr); fflush(stdout); exit(1); } static struct usb_device *next_debug_device(struct usb_device *dev, struct usb_debug_descriptor *debug) { struct usb_bus *bus; if (dev) { bus = dev->bus; goto next; } for (bus = usb_busses; bus; bus = bus->next) { for (dev = bus->devices; dev; dev = dev->next) { struct usb_dev_handle *handle; int ret; #if 1 printf("%02x:%02x\n", dev->descriptor.idVendor, dev->descriptor.idProduct); #endif handle = usb_open(dev); if (!handle) goto next; ret = usb_get_descriptor(handle, USB_DT_DEBUG, 0, debug, sizeof(*debug)); usb_close(handle); #if 1 printf("ret: %d\n", ret); #endif if (ret == sizeof(*debug)) return dev; next: ; } } return NULL; } static int usb_set_debug_mode(usb_dev_handle *handle) { return usb_control_msg(handle, USB_TYPE_STANDARD | USB_RECIP_DEVICE, USB_REQ_SET_FEATURE, USB_FT_DEBUG_MODE, 0, NULL, 0, CTRL_TIMEOUT); } static int usb_unconfigure(usb_dev_handle *handle) { return usb_control_msg(handle, USB_TYPE_STANDARD | USB_RECIP_DEVICE, USB_REQ_SET_CONFIGURATION, 0, 0, NULL, 0, CTRL_TIMEOUT); } static int usb_debug_read(struct usb_device *dev, struct usb_debug_descriptor *debug) { struct usb_dev_handle *handle; char buf[DEBUG_DEVICE_MAX]; int iface, i, j; int ret = -1; /* Find the interface to claim! */ iface = -1; for (i = 0; i < dev->config->interface->num_altsetting; i++) { struct usb_interface_descriptor *face; face = &dev->config->interface->altsetting[i]; for (j = 0; j < face->bNumEndpoints; j++) { if (face->endpoint[j].bEndpointAddress == debug->bDebugInEndpoint) { iface = face->bInterfaceNumber; printf("wMaxPacketSize: %u iface: %d\n", face->endpoint[j].bEndpointAddress, iface); goto found_iface; } } } goto out; found_iface: handle = usb_open(dev); if (!handle) goto out; if ((ret = usb_claim_interface(handle, iface)) < 0) goto out_close; if ((ret = usb_set_debug_mode(handle)) < 0) goto out_release; for (;;) { ret = usb_bulk_read(handle, debug->bDebugInEndpoint, buf, sizeof(buf), 1000000); if (ret < 0) goto out_release; printf("%d:%*.*s", ret, ret, ret, buf); } out_release: usb_release_interface(handle, iface); out_close: usb_close(handle); out: return ret; } static int usb_debug_write(struct usb_device *dev, struct usb_debug_descriptor *debug) { struct usb_dev_handle *handle; char buf[DEBUG_DEVICE_MAX]; int iface, i, j; int ret; ret = -1; /* Find the interface to claim! */ iface = -1; for (i = 0; i < dev->config->interface->num_altsetting; i++) { struct usb_interface_descriptor *face; face = &dev->config->interface->altsetting[i]; for (j = 0; j < face->bNumEndpoints; j++) { if (face->endpoint[j].bEndpointAddress == debug->bDebugOutEndpoint) { iface = face->bInterfaceNumber; printf("wMaxPacketSize: %u iface: %d\n", face->endpoint[j].bEndpointAddress, iface); goto found_iface; } } } goto out; found_iface: handle = usb_open(dev); if (!handle) goto out; if ((ret = usb_claim_interface(handle, iface)) < 0) goto out_close; if ((ret = usb_set_debug_mode(handle)) < 0) goto out_release; for (;;) { if ((ret = read(STDIN_FILENO, buf, sizeof(buf))) <= 0) goto out_shutdown; #if 1 printf("%d:%*.*s", ret, ret, ret, buf); #endif ret = usb_bulk_write(handle, debug->bDebugOutEndpoint, buf, ret, WRITE_TIMEOUT); #if 1 printf("usb_bulk_write: %d\n", ret); #endif if (ret < 0) goto out_shutdown; } out_shutdown: usb_unconfigure(handle); out_release: usb_release_interface(handle, iface); out_close: usb_close(handle); out: return ret; } enum debug_op { DEBUG_LIST = 0, DEBUG_REDIR = 1, DEBUG_READ = 2, DEBUG_WRITE = 3, }; int main(int argc, char **argv) { struct usb_device *dev; struct usb_debug_descriptor debug_desc; int i; int wanted_bus, wanted_dev; int wanted_vendor, wanted_product; enum debug_op op; op = DEBUG_REDIR; wanted_bus = wanted_dev = -1; wanted_vendor = wanted_product = -1; for (i = 1; i < argc; i++) { if (strcmp(argv[i], "-s") == 0) { char *colon; i++; if (i >= argc) die("missing argument"); colon = strchr(argv[i], ':'); if (!colon) wanted_dev = strtoul(argv[i], NULL, 10); else { wanted_bus = strtoul(argv[i], NULL, 10); wanted_dev = strtoul(colon + 1, NULL, 10); } } else if (strcmp(argv[i], "-d") == 0) { char *colon; i++; if (i >= argc) die("missing argument"); wanted_vendor = strtoul(argv[i], NULL, 16); if (colon) wanted_product = strtoul(colon + 1, NULL, 16); } else if (strcmp(argv[i], "-l") == 0) { op = DEBUG_LIST; } else if (strcmp(argv[i], "-r") == 0) { op = DEBUG_READ; } else if (strcmp(argv[i], "-w") == 0) { op = DEBUG_WRITE; } else if (strcmp(argv[i], "-rw") == 0) { op = DEBUG_REDIR; } else { die("Unknown argument: %s\n", argv[i]); } #if 0 if (strcmp(argv[i], "-d") == 0) break; #endif } usb_init(); usb_find_busses(); usb_find_devices(); dev = next_debug_device(NULL, &debug_desc); for (; dev; dev = next_debug_device(dev, &debug_desc)) { int busnum; busnum = strtol(dev->bus->dirname, NULL, 10); if ((wanted_bus != -1) && (busnum != wanted_bus)) continue; if ((wanted_dev != -1) && (dev->devnum != wanted_dev)) continue; if ((wanted_vendor != -1) && (dev->descriptor.idVendor != wanted_vendor)) continue; if ((wanted_product != -1) && (dev->descriptor.idProduct != wanted_product)) continue; if (op != DEBUG_LIST) goto found; printf("%d.%d %04x:%04x\n", busnum, dev->devnum, dev->descriptor.idVendor, dev->descriptor.idProduct); } if (op == DEBUG_LIST) return 0; die("No debug devices found\n"); found: printf("Found one!\n"); printf("desc: %02x %02x %02x %02x\n", debug_desc.bLength, debug_desc.bDescriptorType, debug_desc.bDebugInEndpoint, debug_desc.bDebugOutEndpoint); switch(op) { case DEBUG_READ: usb_debug_read(dev, &debug_desc); break; case DEBUG_WRITE: usb_debug_write(dev, &debug_desc); break; default: die("Unknown operation\n"); } return 0; }