From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1Kg5oA-0002Gk-W0 for qemu-devel@nongnu.org; Wed, 17 Sep 2008 18:47:39 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1Kg5o7-0002Ee-Ta for qemu-devel@nongnu.org; Wed, 17 Sep 2008 18:47:38 -0400 Received: from [199.232.76.173] (port=46931 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Kg5o6-0002E7-Q1 for qemu-devel@nongnu.org; Wed, 17 Sep 2008 18:47:34 -0400 Received: from [67.18.187.6] (port=38545 helo=tjworld.net) by monty-python.gnu.org with esmtps (TLS-1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.60) (envelope-from ) id 1Kg5o4-0006fu-K0 for qemu-devel@nongnu.org; Wed, 17 Sep 2008 18:47:33 -0400 From: TJ In-Reply-To: <48D16904.30104@codemonkey.ws> References: <1220571341.2638.6.camel@hephaestion> <1220580385.2638.15.camel@hephaestion> <48C1346F.3000405@windriver.com> <1220640699.5470.15.camel@hephaestion> <48C1862C.3050307@windriver.com> <1220649226.9611.13.camel@hephaestion> <48C53B04.9030006@windriver.com> <1221679892.17792.6.camel@hephaestion> <48D16904.30104@codemonkey.ws> Content-Type: text/plain Date: Wed, 17 Sep 2008 23:47:27 +0100 Message-Id: <1221691647.17792.55.camel@hephaestion> Mime-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [Qemu-devel] [PATCH] Add USB sys file-system support (v5) Reply-To: qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: kvm On Wed, 2008-09-17 at 15:31 -0500, Anthony Liguori wrote: > Signed-off-by: TJ > > > > A valid Signed-off-by requires a full name, not just an abbreviation. This is valid and full. > usb_host_device_path please. Also, the explicit initialization to 0 is > unnecessary. This should probably be a const char * too? If it were 'const' it would cause a compiler warning with strcpy(usb_host_device_path, devpath) in usb_host_scan(). > > > if (fd < 0) { > > perror(buf); > > goto fail; > > } > > + printf("husb: opened %s\n", buf); > > > > Please don't add unconditional printfs. This was changed to dprintf() as described in the previous precis but the patch-generation accidentally came from older code. > This indenting is wrong. QEMU uses 4-space tabs. Hmmm... something certainly went wrong. The source has 4-space tabs... aha! Forgot to do a "git-add" after "git-reset --soft" when modifying white-space (an interim text editor decided to silently translate spaces to tabs), before "git-commit -C", thus ending up with the working directory copy more recent than the commit, which was the source of "git-format-patch -1". The attached patch *should* be tab-free. > > > 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 term_printfs are also way too verbose. Demoted to dprintf(). -------------------------------------- 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 --- --- a/usb-linux.c 2008-09-17 22:39:38.000000000 +0100 +++ b/usb-linux.c 2008-09-17 23:42:32.000000000 +0100 @@ -7,6 +7,10 @@ * Support for host device auto connect & disconnect * Major rewrite to support fully async operation * + * Copyright 2008 TJ + * 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 @@ -72,9 +76,20 @@ #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 *usb_host_device_path; + +#define USB_FS_NONE 0 +#define USB_FS_PROC 1 +#define USB_FS_DEV 2 +#define USB_FS_SYS 3 + +static int usb_fs_type = 0; /* endpoint association data */ struct endp_data { @@ -890,13 +905,18 @@ printf("husb: open device %d.%d\n", bus_num, addr); - snprintf(buf, sizeof(buf), USBDEVFS_PATH "/%03d/%03d", + if (!usb_host_device_path) { + perror("husb: USB Host Device Path not set"); + goto fail; + } + snprintf(buf, sizeof(buf), "%s/%03d/%03d", usb_host_device_path, bus_num, addr); fd = open(buf, O_RDWR | O_NONBLOCK); if (fd < 0) { perror(buf); goto fail; } + dprintf("husb: opened %s\n", buf); /* read the device description */ dev->descr_len = read(fd, dev->descr, sizeof(dev->descr)); @@ -1038,80 +1058,275 @@ return q - buf; } -static int usb_host_scan(void *opaque, USBScanFunc *func) +/* + 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; + FILE *f = 0; 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]; + int ret = 0; - f = fopen(USBDEVFS_PATH "/devices", "r"); + snprintf(line, sizeof(line), "%s/devices", usb_host_device_path); + f = fopen(line, "r"); if (!f) { - term_printf("husb: could not open %s\n", USBDEVFS_PATH "/devices"); - return 0; + perror("husb: cannot open devices file"); + goto the_end; } + 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 (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); + /* 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. + */ +static int usb_host_scan(void *opaque, USBScanFunc *func) +{ + FILE *f = 0; + DIR *dir = 0; + int ret = 0; + const char *devices = "/devices"; + const char *trying = "husb: trying to open %s%s\n"; + const char *failed = "husb: could not open %s%s\n"; + char devpath[PATH_MAX]; + + // only check the host once + if (!usb_fs_type) { + // test for dev file-system access in /proc/ + dprintf(trying, USBPROCBUS_PATH, devices); + f = fopen(USBPROCBUS_PATH "/devices", "r"); + if (!f) { + dprintf(failed, USBPROCBUS_PATH, devices); + // maybe it has been moved to the /dev/ base + dprintf(trying, USBDEVBUS_PATH, devices); + f = fopen(USBDEVBUS_PATH "/devices", "r"); + if (!f) { + dprintf(failed, USBDEVBUS_PATH, devices); + // test for newer sys file-system access + dprintf(trying, USBSYSBUS_PATH, devices); + dir = opendir(USBSYSBUS_PATH "/devices"); + if (!dir) { + dprintf(failed, USBSYSBUS_PATH, devices); + goto the_end; + } + else { // devices found in /dev/bus/usb/ (yes - not a mistake!) + strcpy(devpath, USBDEVBUS_PATH); + usb_fs_type = USB_FS_SYS; + } + if (dir) closedir(dir); + } + else { // devices found in /dev/bus/usb/ + strcpy(devpath, USBDEVBUS_PATH); + usb_fs_type = USB_FS_DEV; + } + } + else { // devices found in /proc/bus/usb/ + strcpy(devpath, USBPROCBUS_PATH); + usb_fs_type = USB_FS_PROC; + } + if (f) fclose(f); + + // the module setting (used later for opening devices) + usb_host_device_path = qemu_mallocz(strlen(devpath)+1); + if (usb_host_device_path) { + strcpy(usb_host_device_path, devpath); + term_printf("husb: using %s\n", usb_host_device_path); + } + else { // out of memory? + perror("husb: unable to allocate memory for device path"); + goto the_end; + } + } + + switch (usb_fs_type) { + 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; }