This is a white-space clean-up based on Jason Wessel's review on 8th September.
It includes a small addition in the form of a correction for a dprintf() that was part of the patch context before. It doesn't include the suggested alteration to "printf("husb: config #%d need %d\n" since that line is well outside the patch (I believe that belongs to the code Jason was patching with the ioctl issue). -------------------------------------- This patch adds support for host USB devices discovered via: /sys/bus/usb/devices/* and opened from /dev/bus/usb/*/* /dev/bus/usb/devices and opened from /dev/bus/usb/*/* in addition to the existing discovery via: /proc/bus/usb/devices and opened from /proc/bus/usb/*/* Signed-off-by: TJ <[EMAIL PROTECTED]> --- qemu/usb-linux.c | 369 +++++++++++++++++++++++++++++++++++++++++++----------- 1 files changed, 294 insertions(+), 75 deletions(-) diff --git a/qemu/usb-linux.c b/qemu/usb-linux.c index 8ee789f..9b7380c 100644 --- a/qemu/usb-linux.c +++ b/qemu/usb-linux.c @@ -7,6 +7,10 @@ * Support for host device auto connect & disconnect * Magor rewrite to support fully async operation * + * Copyright 2008 TJ <[EMAIL PROTECTED]> + * Added flexible support for /dev/bus/usb /sys/bus/usb/devices in addition + * to the legacy /proc/bus/usb USB device discovery and handling + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -65,9 +69,20 @@ static int usb_host_find_device(int *pbus_num, int *paddr, #define dprintf(...) #endif -#define USBDEVFS_PATH "/proc/bus/usb" +#define USBPROCBUS_PATH "/proc/bus/usb" #define PRODUCT_NAME_SZ 32 #define MAX_ENDPOINTS 16 +#define USBDEVBUS_PATH "/dev/bus/usb" +#define USBSYSBUS_PATH "/sys/bus/usb" + +static char *USBHostDevicePath = 0; + +#define USB_FS_NONE 0 +#define USB_FS_PROC 1 +#define USB_FS_DEV 2 +#define USB_FS_SYS 3 + +static int USBfs = 0; struct sigaction sigact; @@ -600,13 +615,18 @@ static USBDevice *usb_host_device_open_addr(int bus_num, int addr, const char *p printf("husb: open device %d.%d\n", bus_num, addr); - snprintf(buf, sizeof(buf), USBDEVFS_PATH "/%03d/%03d", + if (!USBHostDevicePath) { + perror("husb: USB Host Device Path not set"); + goto fail; + } + snprintf(buf, sizeof(buf), "%s/%03d/%03d", USBHostDevicePath, bus_num, addr); fd = open(buf, O_RDWR | O_NONBLOCK); if (fd < 0) { perror(buf); goto fail; } + printf("husb: opened %s\n", buf); /* read the device description */ dev->descr_len = read(fd, dev->descr, sizeof(dev->descr)); @@ -629,9 +649,10 @@ static USBDevice *usb_host_device_open_addr(int bus_num, int addr, const char *p dev->configuration = 1; /* XXX - do something about initial configuration */ - if (!usb_host_update_interfaces(dev, -1)) + if (!usb_host_update_interfaces(dev, -1)) { + perror("usb_host_device_open: update interfaces"); goto fail; - + } ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci); if (ret < 0) { perror("usb_host_device_open: USBDEVFS_CONNECTINFO"); @@ -717,81 +738,279 @@ static int get_tag_value(char *buf, int buf_size, return q - buf; } +/* + Use /proc/bus/usb/devices or /dev/bus/usb/devices file to determine + host's USB devices. This is legacy support since many distributions + are moving to /sys/bus/usb +*/ +static int usb_host_scan_dev(void *opaque, USBScanFunc *func) +{ + FILE *f = 0; + char line[1024]; + char buf[1024]; + int bus_num, addr, speed, device_count, class_id, product_id, vendor_id; + char product_name[512]; + int ret = 0; + + snprintf(line, sizeof(line), "%s/devices", USBHostDevicePath); + f = fopen(line, "r"); + if (!f) { + perror("husb: cannot open devices file"); + goto the_end; + } + + device_count = 0; + bus_num = addr = speed = class_id = product_id = vendor_id = 0; + for(;;) { + if (fgets(line, sizeof(line), f) == NULL) + break; + if (strlen(line) > 0) + line[strlen(line) - 1] = '\0'; + if (line[0] == 'T' && line[1] == ':') { + if (device_count && (vendor_id || product_id)) { + /* New device. Add the previously discovered device. */ + ret = func(opaque, bus_num, addr, class_id, vendor_id, + product_id, product_name, speed); + if (ret) + goto the_end; + } + if (get_tag_value(buf, sizeof(buf), line, "Bus=", " ") < 0) + goto fail; + + bus_num = atoi(buf); + if (get_tag_value(buf, sizeof(buf), line, "Dev#=", " ") < 0) + goto fail; + + addr = atoi(buf); + if (get_tag_value(buf, sizeof(buf), line, "Spd=", " ") < 0) + goto fail; + + if (!strcmp(buf, "480")) + speed = USB_SPEED_HIGH; + else if (!strcmp(buf, "1.5")) + speed = USB_SPEED_LOW; + else + speed = USB_SPEED_FULL; + product_name[0] = '\0'; + class_id = 0xff; + device_count++; + product_id = 0; + vendor_id = 0; + } + else if (line[0] == 'P' && line[1] == ':') { + if (get_tag_value(buf, sizeof(buf), line, "Vendor=", " ") < 0) + goto fail; + + vendor_id = strtoul(buf, NULL, 16); + if (get_tag_value(buf, sizeof(buf), line, "ProdID=", " ") < 0) + goto fail; + + product_id = strtoul(buf, NULL, 16); + } + else if (line[0] == 'S' && line[1] == ':') { + if (get_tag_value(buf, sizeof(buf), line, "Product=", "") < 0) + goto fail; + + pstrcpy(product_name, sizeof(product_name), buf); + } + else if (line[0] == 'D' && line[1] == ':') { + if (get_tag_value(buf, sizeof(buf), line, "Cls=", " (") < 0) + goto fail; + + class_id = strtoul(buf, NULL, 16); + } + fail: ; + } + if (device_count && (vendor_id || product_id)) { + /* Add the last device. */ + ret = func(opaque, bus_num, addr, class_id, vendor_id, + product_id, product_name, speed); + } + the_end: + if (f) fclose(f); + return ret; +} + +/* + Use /sys/bus/usb/devices/ directory to determine host's USB devices. + + This code is taken from Robert Schiele's original patches posted to the + Novell bug-tracker https://bugzilla.novell.com/show_bug.cgi?id=241950 +*/ +static int usb_host_scan_sys(void *opaque, USBScanFunc *func) +{ + FILE *f; + DIR *dir = 0; + char line[1024]; + int bus_num, addr, speed, class_id, product_id, vendor_id; + int ret = 0; + char product_name[512]; + struct dirent* de; + + dir = opendir(USBSYSBUS_PATH "/devices"); + if (!dir) { + perror("husb: cannot open devices directory"); + goto the_end; + } + + while ((de = readdir(dir))) { + if (de->d_name[0] != '.' && ! strchr(de->d_name, ':')) { + char filename[PATH_MAX]; + char* tmpstr = de->d_name; + if (!strncmp(de->d_name, "usb", 3)) + tmpstr += 3; + + bus_num = atoi(tmpstr); + snprintf(filename, PATH_MAX, USBSYSBUS_PATH "/devices/%s/devnum", de->d_name); + f = fopen(filename, "r"); + if (!f) { + term_printf("Could not open %s\n", filename); + goto the_end; + } + fgets(line, sizeof(line), f); + fclose(f); + addr = atoi(line); + snprintf(filename, PATH_MAX, USBSYSBUS_PATH "/devices/%s/bDeviceClass", de->d_name); + f = fopen(filename, "r"); + if (!f) { + term_printf("Could not open %s\n", filename); + goto the_end; + } + fgets(line, sizeof(line), f); + fclose(f); + class_id = strtoul(line, NULL, 16); + snprintf(filename, PATH_MAX, USBSYSBUS_PATH "/devices/%s/idVendor", de->d_name); + f = fopen(filename, "r"); + if (!f) { + term_printf("Could not open %s\n", filename); + goto the_end; + } + fgets(line, sizeof(line), f); + fclose(f); + vendor_id = strtoul(line, NULL, 16); + snprintf(filename, PATH_MAX, USBSYSBUS_PATH "/devices/%s/idProduct", de->d_name); + f = fopen(filename, "r"); + if (!f) { + term_printf("Could not open %s\n", filename); + goto the_end; + } + fgets(line, sizeof(line), f); + fclose(f); + product_id = strtoul(line, NULL, 16); + snprintf(filename, PATH_MAX, USBSYSBUS_PATH "/devices/%s/product", de->d_name); + f = fopen(filename, "r"); + if (f) { + fgets(line, sizeof(line), f); + fclose(f); + if (strlen(line) > 0) + line[strlen(line) - 1] = '\0'; + + pstrcpy(product_name, sizeof(product_name), line); + } else + *product_name = 0; + + snprintf(filename, PATH_MAX, USBSYSBUS_PATH "/devices/%s/speed", de->d_name); + f = fopen(filename, "r"); + if (!f) { + term_printf("Could not open %s\n", filename); + goto the_end; + } + fgets(line, sizeof(line), f); + fclose(f); + if (!strcmp(line, "480\n")) + speed = USB_SPEED_HIGH; + else if (!strcmp(line, "1.5\n")) + speed = USB_SPEED_LOW; + else + speed = USB_SPEED_FULL; + + ret = func(opaque, bus_num, addr, class_id, vendor_id, + product_id, product_name, speed); + if (ret) + goto the_end; + } + } + the_end: + if (dir) closedir(dir); + return ret; +} + +/* + Determine how to access the host's USB devices and call the specific + support function. + + Introduced to fix Ubuntu LP #156085 + https://bugs.launchpad.net/ubuntu/+bug/156085 + */ static int usb_host_scan(void *opaque, USBScanFunc *func) { - FILE *f; - char line[1024]; - char buf[1024]; - int bus_num, addr, speed, device_count, class_id, product_id, vendor_id; - int ret; - char product_name[512]; + FILE *f = 0; + DIR *dir = 0; + int ret = 0; + char *devices = "/devices"; + char *trying = "husb: trying to open %s%s\n"; + char *failed = "husb: could not open %s%s\n"; + char devpath[PATH_MAX]; + + // only check the host once + if (!USBfs) { + // test for dev file-system access in /proc/ + term_printf(trying, USBPROCBUS_PATH, devices); + f = fopen(USBPROCBUS_PATH "/devices", "r"); + if (!f) { + term_printf(failed, USBPROCBUS_PATH, devices); + // maybe it has been moved to the /dev/ base + term_printf(trying, USBDEVBUS_PATH, devices); + f = fopen(USBDEVBUS_PATH "/devices", "r"); + if (!f) { + term_printf(failed, USBDEVBUS_PATH, devices); + // test for newer sys file-system access + term_printf(trying, USBSYSBUS_PATH, devices); + dir = opendir(USBSYSBUS_PATH "/devices"); + if (!dir) { + term_printf(failed, USBSYSBUS_PATH, devices); + goto the_end; + } + else { // devices found in /dev/bus/usb/ (yes - not a mistake!) + strcpy(devpath, USBDEVBUS_PATH); + USBfs = USB_FS_SYS; + } + if (dir) closedir(dir); + } + else { // devices found in /dev/bus/usb/ + strcpy(devpath, USBDEVBUS_PATH); + USBfs = USB_FS_DEV; + } + } + else { // devices found in /proc/bus/usb/ + strcpy(devpath, USBPROCBUS_PATH); + USBfs = USB_FS_PROC; + } + if (f) fclose(f); + + // the module setting (used later for opening devices) + USBHostDevicePath = qemu_mallocz(strlen(devpath)+1); + if (USBHostDevicePath) { + strcpy(USBHostDevicePath, devpath); + term_printf("husb: using %s\n", USBHostDevicePath); + } + else { // out of memory? + perror("husb: unable to allocate memory for device path"); + goto the_end; + } + } - f = fopen(USBDEVFS_PATH "/devices", "r"); - if (!f) { - term_printf("husb: could not open %s\n", USBDEVFS_PATH "/devices"); - return 0; - } - device_count = 0; - bus_num = addr = speed = class_id = product_id = vendor_id = 0; - ret = 0; - for(;;) { - if (fgets(line, sizeof(line), f) == NULL) - break; - if (strlen(line) > 0) - line[strlen(line) - 1] = '\0'; - if (line[0] == 'T' && line[1] == ':') { - if (device_count && (vendor_id || product_id)) { - /* New device. Add the previously discovered device. */ - ret = func(opaque, bus_num, addr, class_id, vendor_id, - product_id, product_name, speed); - if (ret) - goto the_end; - } - if (get_tag_value(buf, sizeof(buf), line, "Bus=", " ") < 0) - goto fail; - bus_num = atoi(buf); - if (get_tag_value(buf, sizeof(buf), line, "Dev#=", " ") < 0) - goto fail; - addr = atoi(buf); - if (get_tag_value(buf, sizeof(buf), line, "Spd=", " ") < 0) - goto fail; - if (!strcmp(buf, "480")) - speed = USB_SPEED_HIGH; - else if (!strcmp(buf, "1.5")) - speed = USB_SPEED_LOW; - else - speed = USB_SPEED_FULL; - product_name[0] = '\0'; - class_id = 0xff; - device_count++; - product_id = 0; - vendor_id = 0; - } else if (line[0] == 'P' && line[1] == ':') { - if (get_tag_value(buf, sizeof(buf), line, "Vendor=", " ") < 0) - goto fail; - vendor_id = strtoul(buf, NULL, 16); - if (get_tag_value(buf, sizeof(buf), line, "ProdID=", " ") < 0) - goto fail; - product_id = strtoul(buf, NULL, 16); - } else if (line[0] == 'S' && line[1] == ':') { - if (get_tag_value(buf, sizeof(buf), line, "Product=", "") < 0) - goto fail; - pstrcpy(product_name, sizeof(product_name), buf); - } else if (line[0] == 'D' && line[1] == ':') { - if (get_tag_value(buf, sizeof(buf), line, "Cls=", " (") < 0) - goto fail; - class_id = strtoul(buf, NULL, 16); - } - fail: ; - } - if (device_count && (vendor_id || product_id)) { - /* Add the last device. */ - ret = func(opaque, bus_num, addr, class_id, vendor_id, - product_id, product_name, speed); - } + switch (USBfs) { + case USB_FS_PROC: + case USB_FS_DEV: + ret = usb_host_scan_dev(opaque, func); + break; + case USB_FS_SYS: + ret = usb_host_scan_sys(opaque, func); + break; + } the_end: - fclose(f); - return ret; + return ret; } struct USBAutoFilter { -- 1.5.4.3 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html