kvm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] Add USB sys file-system support
@ 2008-09-04 23:35 TJ
  2008-09-05  2:06 ` [PATCH] Add USB sys file-system support (v2) TJ
  0 siblings, 1 reply; 20+ messages in thread
From: TJ @ 2008-09-04 23:35 UTC (permalink / raw)
  To: qemu-devel; +Cc: kvm

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 <linux@tjworld.net>
---
 qemu/usb-linux.c |  329 +++++++++++++++++++++++++++++++++++++++++-------------
 1 files changed, 253 insertions(+), 76 deletions(-)

diff --git a/qemu/usb-linux.c b/qemu/usb-linux.c
index 8ee789f..f263f0c 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 <linux@tjworld.net>
+ *      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,13 @@ 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;
 
 struct sigaction sigact;
 
@@ -600,13 +608,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 +642,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 +731,244 @@ static int get_tag_value(char *buf, int buf_size,
     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(FILE *f, 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];
+	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;
+
+	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:
+	return ret;
+}
 
-    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);
-    }
+/*
+ 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(DIR *dir, void *opaque, USBScanFunc *func)
+{
+	FILE *f;
+	char line[1024];
+	int bus_num, addr, speed, class_id, product_id, vendor_id;
+	int ret = 0;
+	char product_name[512];
+	struct dirent* de;
+
+	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, "/sys/bus/usb/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, "/sys/bus/usb/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, "/sys/bus/usb/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, "/sys/bus/usb/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, "/sys/bus/usb/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, "/sys/bus/usb/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);
+		}
+	}
+ the_end:
+     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 = 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];
+
+	// initialise the module setting
+	USBHostDevicePath = 0;
+
+	// 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);
+		}
+		else // devices found in /dev/bus/usb/
+			strcpy(devpath, USBDEVBUS_PATH);
+	}
+	else // devices found in /proc/bus/usb/
+		strcpy(devpath, USBPROCBUS_PATH);
+
+	// the module setting (used later for opening devices)
+	USBHostDevicePath = qemu_mallocz(strlen(devpath)+1);
+	strcpy(USBHostDevicePath, devpath);
+	term_printf("husb: using %s\n", USBHostDevicePath);
+
+	if(f) { // dev file-system access
+		ret = usb_host_scan_dev(f, opaque, func);
+		fclose(f);
+	} else if(dir) { // sys file-system access
+		ret = usb_host_scan_sys(dir, opaque, func);
+		closedir(dir);
+	}
  the_end:
-    fclose(f);
-    return ret;
+	return ret;
 }
 
 struct USBAutoFilter {
-- 
1.5.4.3



^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH] Add USB sys file-system support (v2)
  2008-09-04 23:35 [PATCH] Add USB sys file-system support TJ
@ 2008-09-05  2:06 ` TJ
  2008-09-05 13:30   ` [Qemu-devel] " Jason Wessel
  0 siblings, 1 reply; 20+ messages in thread
From: TJ @ 2008-09-05  2:06 UTC (permalink / raw)
  To: qemu-devel; +Cc: kvm

Revision 2.

I realised I'd made a major programming boo-boo despite knowing better -
requesting an allocation of memory in the host USB file-system scan
function, forgetting that the function isn't just called once but
repeatedly. That would have led to orphaned memory allocations each time
a USB scan or open operation occurred - baaad!

I've also changed the logic so it only scans for the USB file-system
type the first time. After that it works off stored values.

=======
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 <linux@tjworld.net>
---
 qemu/usb-linux.c |  367 +++++++++++++++++++++++++++++++++++++++++++-----------
 1 files changed, 292 insertions(+), 75 deletions(-)

diff --git a/qemu/usb-linux.c b/qemu/usb-linux.c
index 8ee789f..40fce47 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 <linux@tjworld.net>
+ *      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,277 @@ 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);
+		}
+	}
+ 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



^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [Qemu-devel] [PATCH] Add USB sys file-system support (v2)
  2008-09-05  2:06 ` [PATCH] Add USB sys file-system support (v2) TJ
@ 2008-09-05 13:30   ` Jason Wessel
  2008-09-05 18:51     ` TJ
  2008-09-05 19:20     ` [Qemu-devel] [PATCH] Add USB sys file-system support (v2) TJ
  0 siblings, 2 replies; 20+ messages in thread
From: Jason Wessel @ 2008-09-05 13:30 UTC (permalink / raw)
  To: qemu-devel, linux; +Cc: kvm

TJ wrote:
> Revision 2.
>
> I realised I'd made a major programming boo-boo despite knowing better -
> requesting an allocation of memory in the host USB file-system scan
> function, forgetting that the function isn't just called once but
> repeatedly. That would have led to orphaned memory allocations each time
> a USB scan or open operation occurred - baaad!
>
> I've also changed the logic so it only scans for the USB file-system
> type the first time. After that it works off stored values.
>
>   

Perhaps there is more work to do with this patch, or there are other
pieces still pending?

I tried out the patch because it looked reasonably interesting on ubuntu
7.10 64bit, and looked like a nice way to attach a local USB device, but
it did not quite work.

IE:
(qemu) info usbhost
  Device 3.2, speed 12 Mb/s
    Class 00: USB device 067b:2303, USB-Serial Controller


The first thing I tried was using it with the vendor/product id and it
failed immediately.

qemu ... -usb -usbdevice host:067b:2303
Warning: could not add USB device host:067b:2303

Then I tried using it with bus.addr syntax:

qemu ... -usb -usbdevice host:003.002
husb: open device 3.2
husb: opened /dev/bus/usb/003/002
husb: config #1 need -1
husb: 1 interfaces claimed for configuration -1
husb: grabbed usb device 3.2
usb_linux_update_endp_table: Broken pipe
Warning: could not add USB device host:003.002



It turns out that it is failing on the ioctl in usb-linux.c


    541         ct.bRequestType = USB_DIR_IN | USB_RECIP_INTERFACE;
    542         ct.bRequest = USB_REQ_GET_INTERFACE;
    543         ct.wValue = 0;
    544         ct.wIndex = interface;
    545         ct.wLength = 1;
    546         ct.data = &alt_interface;
    547         ct.timeout = 50;
    548
    549         ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);
    550         if (ret < 0) {
    551             perror("usb_linux_update_endp_table");
    552             return 1;
    553         }


I can see that some of the ioctls succeed so perhaps it is partially
working.  Any ideas around why this might be failing?  I had not ever
looked at the qemu usb code before, but the -1 for the configuration did
look a bit suspicious . 

Cheers,
Jason.

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Qemu-devel] [PATCH] Add USB sys file-system support (v2)
  2008-09-05 13:30   ` [Qemu-devel] " Jason Wessel
@ 2008-09-05 18:51     ` TJ
  2008-09-05 19:19       ` Jason Wessel
  2008-09-05 19:20     ` [Qemu-devel] [PATCH] Add USB sys file-system support (v2) TJ
  1 sibling, 1 reply; 20+ messages in thread
From: TJ @ 2008-09-05 18:51 UTC (permalink / raw)
  To: Jason Wessel; +Cc: qemu-devel, kvm

On Fri, 2008-09-05 at 08:30 -0500, Jason Wessel wrote:
> I tried out the patch because it looked reasonably interesting on ubuntu
> 7.10 64bit, and looked like a nice way to attach a local USB device, but
> it did not quite work.

What version of kvm, or what was the commit HEAD hash?

What does the patch report as the method of access to the USB
file-system? The first time usb_host_scan() is called it reports its
attempts to find a suitable access method.

Does the same device work without the patch? The device is a
USB-to-serial converter? Is there a host process attached to it? ( USB
device raw access requires the host to release the device or you'll get
all kinds of problems and potential data corruption if it is a block
device).

The location of the error you report is outside the scope of the patch
itself. The patch is only responsible for determining the available
devices and listing them.

The issue you're experiencing could be related to the recent changes to
USB support introduced by Max.


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Qemu-devel] [PATCH] Add USB sys file-system support (v2)
  2008-09-05 18:51     ` TJ
@ 2008-09-05 19:19       ` Jason Wessel
  2008-09-05 20:28         ` TJ
  2008-09-05 21:13         ` [PATCH] Add USB sys file-system support (v3) TJ
  0 siblings, 2 replies; 20+ messages in thread
From: Jason Wessel @ 2008-09-05 19:19 UTC (permalink / raw)
  To: TJ; +Cc: qemu-devel, kvm

TJ wrote:
> On Fri, 2008-09-05 at 08:30 -0500, Jason Wessel wrote:
>   
>> I tried out the patch because it looked reasonably interesting on ubuntu
>> 7.10 64bit, and looked like a nice way to attach a local USB device, but
>> it did not quite work.
>>     
>
> What version of kvm, or what was the commit HEAD hash?
>   

Since you posed this to the qemu-devel mailing list, I tried it on the
QEMU development head.

> What does the patch report as the method of access to the USB
> file-system? 
husb: using /dev/bus/usb

> Does the same device work without the patch? 

Of course not, because the host does not have /proc/bus/usb.

The device is known to work fine if the host driver is loaded.

> The device is a
> USB-to-serial converter? Is there a host process attached to it? 
It is a pl2303 rs232 usb device.  And there is definitely no
host process or any host driver loaded.

> ( USB
> device raw access requires the host to release the device or you'll get
> all kinds of problems and potential data corruption if it is a block
> device).
>
> The location of the error you report is outside the scope of the patch
> itself. The patch is only responsible for determining the available
> devices and listing them.
>
>   
I know it is outside the patch which enables the usb searching, which is
why I asked if there are more pieces.

What might be a defect is that it did not work with the
|host:vendor_id:product_id and immediately failed.|


> The issue you're experiencing could be related to the recent changes to
> USB support introduced by Max.
>
>   
I am guessing it is unique to this class of device or perhaps even this
particular device.  When I by bypassed the failing ioctl, the device
worked to write to it (ie it echo characters), but not to read from it
(not at the usb level) but rather the rs232 level.  I assume this is
because it is selecting the wrong end points to hook up or something or
that the failed ioctl really does need to succeed. :-)

Jason.

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Qemu-devel] [PATCH] Add USB sys file-system support (v2)
  2008-09-05 13:30   ` [Qemu-devel] " Jason Wessel
  2008-09-05 18:51     ` TJ
@ 2008-09-05 19:20     ` TJ
  1 sibling, 0 replies; 20+ messages in thread
From: TJ @ 2008-09-05 19:20 UTC (permalink / raw)
  To: Jason Wessel; +Cc: qemu-devel, kvm

On Fri, 2008-09-05 at 08:30 -0500, Jason Wessel wrote:
> I tried out the patch because it looked reasonably interesting on ubuntu
> 7.10 64bit, and looked like a nice way to attach a local USB device, but
> it did not quite work.
> 
> IE:
> (qemu) info usbhost
>   Device 3.2, speed 12 Mb/s
>     Class 00: USB device 067b:2303, USB-Serial Controller

Jason, I think this is related to handling the USB serial device. Try
another USB device - a flash-memory key for example.

Here's the results of my tests:

Host is Ubuntu Hardy amd64 8.04.1 (2.6.24-21-generic).
VM guest is Ubuntu Gutsy server (2.6.22-14-server)
hypervisor is kvm-74.

I think there is a problem with the usb_add name functions - the
host:VID:PID rarely worked for me so I always use host:Bus.Device
format.

I've got a USB-to-serial converter here too:

Bus 001 Device 004: ID 0711:0230 Magic Control Technology Corp. MCT-232 Serial Port

Here's the output I get:

usb_add host:1.4

husb: open device 1.4
husb: opened /dev/bus/usb/001/004
husb: config #1 need -1
husb: 1 interfaces claimed for configuration -1
husb: grabbed usb device 1.4
usb_linux_update_endp_table: Broken pipe

If however I add a USB flash key:

Bus 005 Device 016: ID 0781:5151 SanDisk Corp. Cruzer Micro 256/512MB Flash Drive

usb_add host:5.16

husb: open device 5.16
husb: opened /dev/bus/usb/005/016
husb: config #1 need -1
husb: 1 interfaces claimed for configuration -1
husb: grabbed usb device 5.16
husb: config #1 need 1
husb: 1 interfaces claimed for configuration 1
husb: config #1 need 1
husb: 1 interfaces claimed for configuration 1

and the device appears and is mountable in the VM.


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Qemu-devel] [PATCH] Add USB sys file-system support (v2)
  2008-09-05 19:19       ` Jason Wessel
@ 2008-09-05 20:28         ` TJ
  2008-09-05 20:54           ` Jason Wessel
  2008-09-05 21:13         ` [PATCH] Add USB sys file-system support (v3) TJ
  1 sibling, 1 reply; 20+ messages in thread
From: TJ @ 2008-09-05 20:28 UTC (permalink / raw)
  To: Jason Wessel; +Cc: qemu-devel, kvm

On Fri, 2008-09-05 at 14:19 -0500, Jason Wessel wrote:
> > What version of kvm, or what was the commit HEAD hash?
> >   
> 
> Since you posed this to the qemu-devel mailing list, I tried it on the
> QEMU development head.

I've posted to qemu-devel and kvm-devel, working primary with the kvm
release packaging it for Ubuntu Gutsy/Hardy/Intrepid.

> 
> > What does the patch report as the method of access to the USB
> > file-system? 
> husb: using /dev/bus/usb
> 
> > Does the same device work without the patch? 
> 
> Of course not, because the host does not have /proc/bus/usb.

If you're using Ubuntu you can easily test with /proc/bus/usb by editing
the comments out to enable the 'magic lines' in 
/etc/init.d/mountdevsubfs.sh or issue them manually:

#
# Magic to make /proc/bus/usb work
#
#mkdir -p /dev/bus/usb/.usbfs
#domount usbfs "" /dev/bus/usb/.usbfs -obusmode=0700,devmode=0600,listmode=0644
#ln -s .usbfs/devices /dev/bus/usb/devices
#mount --rbind /dev/bus/usb /proc/bus/usb


> What might be a defect is that it did not work with the
> |host:vendor_id:product_id and immediately failed.

Yes, I've been looking at that. Although the code-path goes through the
patch - usb_host_scan() - it simply passed the structures and function
pointer on without touching them. I'm currently analysing it with some
dprintf() entries to see why usb_host_find_device() doesn't get the
device.

> I am guessing it is unique to this class of device or perhaps even this
> particular device.

I agree, maybe it is the serial character-based devices. As I can
reproduce it with a different VID:PID of the same class it seems more
likely.


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Qemu-devel] [PATCH] Add USB sys file-system support (v2)
  2008-09-05 20:28         ` TJ
@ 2008-09-05 20:54           ` Jason Wessel
  0 siblings, 0 replies; 20+ messages in thread
From: Jason Wessel @ 2008-09-05 20:54 UTC (permalink / raw)
  To: TJ; +Cc: qemu-devel, kvm

TJ wrote:
> 
> I agree, maybe it is the serial character-based devices. As I can
> reproduce it with a different VID:PID of the same class it seems more
> likely.
> 


The usb serial devices do not appear to have an alternate interface
and this particular ioctl will always fail for the usb serial driver
in the host kernel.  It might not be the right way to fix it (see
patch below), but it does cause the device to actually work correctly
in the guest.

At this point I was able to use the rs232 usb dongle in the guest
looped back to the rs232 port on the host's motherboard via a null
modem.  This means I can now debug the usb linux console driver with
qemu. :-)

Many thanks for your adding in the code to read from /dev/bus/usb.

Jason.

---
 usb-linux.c |    3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

--- a/usb-linux.c
+++ b/usb-linux.c
@@ -548,8 +548,7 @@ static int usb_linux_update_endp_table(U
 
         ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);
         if (ret < 0) {
-            perror("usb_linux_update_endp_table");
-            return 1;
+                alt_interface = interface;
         }
 
         /* the current interface descriptor is the active interface


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH] Add USB sys file-system support (v3)
  2008-09-05 19:19       ` Jason Wessel
  2008-09-05 20:28         ` TJ
@ 2008-09-05 21:13         ` TJ
  2008-09-08 14:47           ` Jason Wessel
  1 sibling, 1 reply; 20+ messages in thread
From: TJ @ 2008-09-05 21:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: kvm, Jason Wessel

Thanks to Jason Wessel for spotting that when using /sys fs for
discovering devices, the usb_add host:VID:PID form failed. This was due
to the device scanning loop not breaking out when the indirect calls to
usb_host_find_device_scan() via function pointers were performed, and a
device match was made.

=======

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 <linux@tjworld.net>
---
 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 <linux@tjworld.net>
+ *      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



^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [PATCH] Add USB sys file-system support (v3)
  2008-09-05 21:13         ` [PATCH] Add USB sys file-system support (v3) TJ
@ 2008-09-08 14:47           ` Jason Wessel
  2008-09-17 19:31             ` [PATCH] Add USB sys file-system support (v4) TJ
  0 siblings, 1 reply; 20+ messages in thread
From: Jason Wessel @ 2008-09-08 14:47 UTC (permalink / raw)
  To: TJ; +Cc: qemu-devel, kvm

TJ,

The v3 usb patch looks good to me and works well.  When used in
conjunction with ioctl() work around I mentioned before, I was able to
use QEMU to quickly find and fix a 2 different 2.6.27 usb serial
regressions. :-)

It would be great to push this into the qemu development tree.

I see two minor problems with your patch for pushing it into the qemu
development tree.

1) Some white space issues
     - In the patch it has mixed spaces and tabs
     - The tabs should be 8 spaces
     - This qemu source file has the standard 4 space indentation

2) Minor printf() clean ups

   The printf() on line 614 should be a dprintf()  IE:

     printf("husb: open device %d.%d\n", bus_num, addr);

   - I realize this was not one that you added in your patch,
     but I looked at the call stack to see the prior ways this
     was used, all the messages of this type were dprintf()
     This comment is also based on the printf() you added
     later in the same function.
   
   The printf() on line 627 should be a term_printf() assuming
   you deem it is important to provide this up to the end user.  IE:

     printf("husb: config #%d need %d\n", dev->descr[i + 5], configuration);


Reviewed-by: Jason Wessel <jason.wessel@windriver.com>

Fixing those two minor issues, I would consider the patch ready to commit.

Cheers,
Jason.


TJ wrote:
>
> =======
>
> 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 <linux@tjworld.net>
> ---
>  qemu/usb-linux.c |  369
+++++++++++++++++++++++++++++++++++++++++++-----------
>  1 files changed, 294 insertions(+), 75 deletions(-)



^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH] Add USB sys file-system support (v4)
  2008-09-08 14:47           ` Jason Wessel
@ 2008-09-17 19:31             ` TJ
  2008-09-17 20:31               ` Anthony Liguori
  0 siblings, 1 reply; 20+ messages in thread
From: TJ @ 2008-09-17 19:31 UTC (permalink / raw)
  To: qemu-devel; +Cc: kvm, Jason Wessel

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 <linux@tjworld.net>
---
 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 <linux@tjworld.net>
+ *      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



^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [PATCH] Add USB sys file-system support (v4)
  2008-09-17 19:31             ` [PATCH] Add USB sys file-system support (v4) TJ
@ 2008-09-17 20:31               ` Anthony Liguori
  2008-09-17 22:47                 ` [PATCH] Add USB sys file-system support (v5) TJ
  0 siblings, 1 reply; 20+ messages in thread
From: Anthony Liguori @ 2008-09-17 20:31 UTC (permalink / raw)
  To: TJ; +Cc: qemu-devel, kvm, Jason Wessel

TJ wrote:
> 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 <linux@tjworld.net>
>   

A valid Signed-off-by requires a full name, not just an abbreviation.

> +
> +static char *USBHostDevicePath = 0;
>   

usb_host_device_path please.  Also, the explicit initialization to 0 is 
unnecessary.  This should probably be a const char * too?

> +#define USB_FS_NONE 0
> +#define USB_FS_PROC 1
> +#define USB_FS_DEV 2
> +#define USB_FS_SYS 3
> +
> +static int USBfs = 0;
>   

usb_fs_type.

>  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);
>   

Please don't add unconditional printfs.
> +/*
> + 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))) {
>   

This indenting is wrong.  QEMU uses 4-space tabs.

> +
> +/*
> + 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
> + */
>   

Please don't add these sorts of references.  They quickly become stale 
as code changes.

>  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 depth of this indentation is nuts.  The term_printfs are also way 
too verbose.

Did you reindent a bunch of existing code?  It's hard to tell from this 
patch.  If so, please don't do that sort of thing in a patching adding 
functionality.  It makes it very hard to review.

Regards,

Anthony Liguori


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH] Add USB sys file-system support (v5)
  2008-09-17 20:31               ` Anthony Liguori
@ 2008-09-17 22:47                 ` TJ
  2008-09-22 22:37                   ` Anthony Liguori
  0 siblings, 1 reply; 20+ messages in thread
From: TJ @ 2008-09-17 22:47 UTC (permalink / raw)
  To: qemu-devel; +Cc: kvm

On Wed, 2008-09-17 at 15:31 -0500, Anthony Liguori wrote:

> Signed-off-by: TJ <linux@tjworld.net>
> >   
> 
> 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 <linux@tjworld.net>
---
--- 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 <linux@tjworld.net>
+ *      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;
 }
 


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH] Add USB sys file-system support (v5)
  2008-09-17 22:47                 ` [PATCH] Add USB sys file-system support (v5) TJ
@ 2008-09-22 22:37                   ` Anthony Liguori
  2008-09-23  1:23                     ` [Qemu-devel] " TJ
  2008-09-23  1:33                     ` [PATCH] Add USB sys file-system support (v6) TJ
  0 siblings, 2 replies; 20+ messages in thread
From: Anthony Liguori @ 2008-09-22 22:37 UTC (permalink / raw)
  To: TJ; +Cc: qemu-devel, kvm

TJ wrote:
> 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 <linux@tjworld.net>
>   

This patch is still white spaced damaged.

> ---
> --- a/usb-linux.c   2008-09-17 22:39:38.000000000 +0100
> +++ b/usb-linux.c   2008-09-17 23:42:32.000000000 +0100
>   

This chunk:

> -        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: ;
>   

Is identical to this chunk with the exception of whitespace.  But 
curiously, not enough white space to warrant such a large diff.  I broke 
out ediff-buffers to verify this.  Did you reformat this whole region 
and then just query-replace the tabs with spaces?  I can't see how diff 
would generate this chunk otherwise.

There should be no changes here.  I don't mean to be pedantic but it's 
extremely difficult to review a patch like this.

> +        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);
>   

Regards,

Anthony Liguori

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Qemu-devel] Re: [PATCH] Add USB sys file-system support (v5)
  2008-09-22 22:37                   ` Anthony Liguori
@ 2008-09-23  1:23                     ` TJ
  2008-09-23  1:33                     ` [PATCH] Add USB sys file-system support (v6) TJ
  1 sibling, 0 replies; 20+ messages in thread
From: TJ @ 2008-09-23  1:23 UTC (permalink / raw)
  To: qemu-devel; +Cc: kvm

On Mon, 2008-09-22 at 17:37 -0500, Anthony Liguori wrote:

> This patch is still white spaced damaged.

> Is identical to this chunk with the exception of whitespace.  But 
> curiously, not enough white space to warrant such a large diff.  I broke 
> out ediff-buffers to verify this.  Did you reformat this whole region 
> and then just query-replace the tabs with spaces?  I can't see how diff 
> would generate this chunk otherwise.
> 
> There should be no changes here.  I don't mean to be pedantic but it's 
> extremely difficult to review a patch like this.

I suspect it is because I copy/pasted that code from its original
location in usb_host_scan() to the new usb_host_scan_dev(), and
subsequently did some shuffling about.

Could it also be because that hunk has moved both location and
containing function? I was trying to figure out in my head how diff
would efficiently handle that but gave up :)

It looks as if I need to recreate the new source version again manually,
making sure the editor doesn't mess with tabs.



^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH] Add USB sys file-system support (v6)
  2008-09-22 22:37                   ` Anthony Liguori
  2008-09-23  1:23                     ` [Qemu-devel] " TJ
@ 2008-09-23  1:33                     ` TJ
  2008-09-25 17:45                       ` Anthony Liguori
  2008-10-01 21:21                       ` [PATCH] Add USB sys file-system support (v7) TJ
  1 sibling, 2 replies; 20+ messages in thread
From: TJ @ 2008-09-23  1:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: kvm

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 <linux@tjworld.net>
---
--- a/usb-linux.c	2008-09-17 22:39:38.000000000 +0100
+++ b/usb-linux.c	2008-09-23 02:28:48.000000000 +0100
@@ -7,6 +7,10 @@
  *      Support for host device auto connect & disconnect
  *      Major rewrite to support fully async operation
  *
+ * Copyright 2008 TJ <linux@tjworld.net>
+ *      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,23 +1058,29 @@
     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;
@@ -1106,12 +1132,191 @@
     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;
 }
 


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH] Add USB sys file-system support (v6)
  2008-09-23  1:33                     ` [PATCH] Add USB sys file-system support (v6) TJ
@ 2008-09-25 17:45                       ` Anthony Liguori
  2008-10-01 21:21                       ` [PATCH] Add USB sys file-system support (v7) TJ
  1 sibling, 0 replies; 20+ messages in thread
From: Anthony Liguori @ 2008-09-25 17:45 UTC (permalink / raw)
  To: TJ; +Cc: qemu-devel, kvm

TJ wrote:
> 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 <linux@tjworld.net>
> ---
> --- a/usb-linux.c	2008-09-17 22:39:38.000000000 +0100
> +++ b/usb-linux.c	2008-09-23 02:28:48.000000000 +0100
> @@ -7,6 +7,10 @@
>   *      Support for host device auto connect & disconnect
>   *      Major rewrite to support fully async operation
>   *
> + * Copyright 2008 TJ <linux@tjworld.net>
> + *      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);
>   

You have tabs here.

>      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,23 +1058,29 @@
>      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;
>      }
>   

And here and almost everywhere.

> +
>      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;
> @@ -1106,12 +1132,191 @@
>      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;
>   

This is indented wrong.

> +
> +    		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!)
>   

else belongs on the same line as curly brackets.  Please avoid C99 
comments too.

Regards,

Anthony Liguori

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH] Add USB sys file-system support (v7)
  2008-09-23  1:33                     ` [PATCH] Add USB sys file-system support (v6) TJ
  2008-09-25 17:45                       ` Anthony Liguori
@ 2008-10-01 21:21                       ` TJ
  2008-10-01 23:19                         ` [PATCH] Add USB sys file-system support (v8) TJ
  1 sibling, 1 reply; 20+ messages in thread
From: TJ @ 2008-10-01 21:21 UTC (permalink / raw)
  To: qemu-devel; +Cc: kvm

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 <linux@tjworld.net>
---
 usb-linux.c |  228 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 218 insertions(+), 10 deletions(-)

diff --git a/usb-linux.c b/usb-linux.c
index c5da5b5..5f0eeaf 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -7,6 +7,10 @@
  *      Support for host device auto connect & disconnect
  *      Major rewrite to support fully async operation
  *
+ * Copyright 2008 TJ <linux@tjworld.net>
+ *      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 @@ 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 *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;
 
 /* endpoint association data */
 struct endp_data {
@@ -890,13 +905,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 (!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,23 +1058,33 @@ static int get_tag_value(char *buf, int buf_size,
     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");
+    if (!usb_host_device_path) {
+        perror("husb: USB Host Device Path not set");
+        goto the_end;
+    }
+    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;
@@ -1111,7 +1141,185 @@ static int usb_host_scan(void *opaque, USBScanFunc *func)
                    product_id, product_name, speed);
     }
  the_end:
-    fclose(f);
+    if (f)
+        fclose(f);
+    return ret;
+}
+
+/*
+ * Read sys file-system device file
+ *
+ * @line address of buffer to put file contents in
+ * @line_size size of line
+ * @device_file path to device file (printf format string)
+ * @device_name device being opened (inserted into device_file)
+ *
+ * @return 0 failed, 1 succeeded ('line' contains data)
+ */
+static int usb_host_read_file(char *line, size_t line_size, const char *device_file, const char *device_name)
+{
+    FILE *f;
+    int ret = 0;
+    char filename[PATH_MAX];
+
+    snprintf(filename, PATH_MAX, device_file, device_name);
+    f = fopen(filename, "r");
+    if (f) {
+        fgets(line, line_size, f);
+        fclose(f);
+        ret = 1;
+    } else {
+        term_printf("husb: could not open %s\n", filename);
+    }
+
+    return ret;
+}
+
+/*
+ * Use /sys/bus/usb/devices/ directory to determine host's USB
+ * devices.
+ *
+ * This code is based on 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)
+{
+    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 *tmpstr = de->d_name;
+            if (!strncmp(de->d_name, "usb", 3))
+                tmpstr += 3;
+            bus_num = atoi(tmpstr);
+
+            if (!usb_host_read_file(line, sizeof(line), USBSYSBUS_PATH "/devices/%s/devnum", de->d_name))
+                goto the_end;
+            if (sscanf(line, "%d", &addr) != 1)
+                goto the_end;
+
+            if (!usb_host_read_file(line, sizeof(line), USBSYSBUS_PATH "/devices/%s/bDeviceClass", de->d_name))
+                goto the_end;
+            if (sscanf(line, "%x", &class_id) != 1)
+                goto the_end;
+
+            if (!usb_host_read_file(line, sizeof(line), USBSYSBUS_PATH "/devices/%s/idVendor", de->d_name))
+                goto the_end;
+            if (sscanf(line, "%x", &vendor_id) != 1)
+                goto the_end;
+
+            if (!usb_host_read_file(line, sizeof(line), USBSYSBUS_PATH "/devices/%s/idProduct", de->d_name))
+                goto the_end;
+            if (sscanf(line, "%x", &product_id) != 1)
+                goto the_end;
+
+            if (!usb_host_read_file(line, sizeof(line), USBSYSBUS_PATH "/devices/%s/product", de->d_name)) {
+                *product_name = 0;
+            } else {
+                if (strlen(line) > 0)
+                    line[strlen(line) - 1] = '\0';
+                pstrcpy(product_name, sizeof(product_name), line);
+            }
+
+            if (!usb_host_read_file(line, sizeof(line), USBSYSBUS_PATH "/devices/%s/speed", de->d_name))
+                goto the_end;
+            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 *opened = "husb: opened %s%s\n";
+    const char *fs_type[] = {"unknown", "proc", "dev", "sys"};
+    char devpath[PATH_MAX];
+
+    /* only check the host once */
+    if (!usb_fs_type) {
+        f = fopen(USBPROCBUS_PATH "/devices", "r");
+        if (f) {
+            /* devices found in /proc/bus/usb/ */
+            strcpy(devpath, USBPROCBUS_PATH);
+            usb_fs_type = USB_FS_PROC;
+            fclose(f);
+            dprintf(opened, USBPROCBUS_PATH, devices);
+        }
+        /* try additional methods if an access method hasn't been found yet */
+        f = fopen(USBDEVBUS_PATH "/devices", "r");
+        if (!usb_fs_type && f) {
+            /* devices found in /dev/bus/usb/ */
+            strcpy(devpath, USBDEVBUS_PATH);
+            usb_fs_type = USB_FS_DEV;
+            fclose(f);
+            dprintf(opened, USBDEVBUS_PATH, devices);
+        }
+        dir = opendir(USBSYSBUS_PATH "/devices");
+        if (!usb_fs_type && f) {
+            /* devices found in /dev/bus/usb/ (yes - not a mistake!) */
+            strcpy(devpath, USBDEVBUS_PATH);
+            usb_fs_type = USB_FS_SYS;
+            closedir(dir);
+            dprintf(opened, USBSYSBUS_PATH, devices);
+        } else {
+            term_printf("husb: unable to access USB devices\n");
+            goto the_end;
+        }
+
+        /* 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 file-system with %s\n", fs_type[usb_fs_type], 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:
     return ret;
 }
 
-- 
1.5.4.3



^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH] Add USB sys file-system support (v8)
  2008-10-01 21:21                       ` [PATCH] Add USB sys file-system support (v7) TJ
@ 2008-10-01 23:19                         ` TJ
  2008-10-07 20:09                           ` Anthony Liguori
  0 siblings, 1 reply; 20+ messages in thread
From: TJ @ 2008-10-01 23:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: kvm

A bug crept into the version 7 patch whilst editing to help pass
checkpatch.pl tests. Inadvertently, in moving an assignment out of an
if() condition I replaced it with a test against the wrong variable.
This is the corrected patch.
======
Add USB sys file-system support

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 <linux@tjworld.net>
---
 usb-linux.c |  228 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 218 insertions(+), 10 deletions(-)

diff --git a/usb-linux.c b/usb-linux.c
index c5da5b5..6113a0c 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -7,6 +7,10 @@
  *      Support for host device auto connect & disconnect
  *      Major rewrite to support fully async operation
  *
+ * Copyright 2008 TJ <linux@tjworld.net>
+ *      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 @@ 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 *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;
 
 /* endpoint association data */
 struct endp_data {
@@ -890,13 +905,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 (!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,23 +1058,33 @@ static int get_tag_value(char *buf, int buf_size,
     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");
+    if (!usb_host_device_path) {
+        perror("husb: USB Host Device Path not set");
+        goto the_end;
+    }
+    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;
@@ -1111,7 +1141,185 @@ static int usb_host_scan(void *opaque, USBScanFunc *func)
                    product_id, product_name, speed);
     }
  the_end:
-    fclose(f);
+    if (f)
+        fclose(f);
+    return ret;
+}
+
+/*
+ * Read sys file-system device file
+ *
+ * @line address of buffer to put file contents in
+ * @line_size size of line
+ * @device_file path to device file (printf format string)
+ * @device_name device being opened (inserted into device_file)
+ *
+ * @return 0 failed, 1 succeeded ('line' contains data)
+ */
+static int usb_host_read_file(char *line, size_t line_size, const char *device_file, const char *device_name)
+{
+    FILE *f;
+    int ret = 0;
+    char filename[PATH_MAX];
+
+    snprintf(filename, PATH_MAX, device_file, device_name);
+    f = fopen(filename, "r");
+    if (f) {
+        fgets(line, line_size, f);
+        fclose(f);
+        ret = 1;
+    } else {
+        term_printf("husb: could not open %s\n", filename);
+    }
+
+    return ret;
+}
+
+/*
+ * Use /sys/bus/usb/devices/ directory to determine host's USB
+ * devices.
+ *
+ * This code is based on 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)
+{
+    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 *tmpstr = de->d_name;
+            if (!strncmp(de->d_name, "usb", 3))
+                tmpstr += 3;
+            bus_num = atoi(tmpstr);
+
+            if (!usb_host_read_file(line, sizeof(line), USBSYSBUS_PATH "/devices/%s/devnum", de->d_name))
+                goto the_end;
+            if (sscanf(line, "%d", &addr) != 1)
+                goto the_end;
+
+            if (!usb_host_read_file(line, sizeof(line), USBSYSBUS_PATH "/devices/%s/bDeviceClass", de->d_name))
+                goto the_end;
+            if (sscanf(line, "%x", &class_id) != 1)
+                goto the_end;
+
+            if (!usb_host_read_file(line, sizeof(line), USBSYSBUS_PATH "/devices/%s/idVendor", de->d_name))
+                goto the_end;
+            if (sscanf(line, "%x", &vendor_id) != 1)
+                goto the_end;
+
+            if (!usb_host_read_file(line, sizeof(line), USBSYSBUS_PATH "/devices/%s/idProduct", de->d_name))
+                goto the_end;
+            if (sscanf(line, "%x", &product_id) != 1)
+                goto the_end;
+
+            if (!usb_host_read_file(line, sizeof(line), USBSYSBUS_PATH "/devices/%s/product", de->d_name)) {
+                *product_name = 0;
+            } else {
+                if (strlen(line) > 0)
+                    line[strlen(line) - 1] = '\0';
+                pstrcpy(product_name, sizeof(product_name), line);
+            }
+
+            if (!usb_host_read_file(line, sizeof(line), USBSYSBUS_PATH "/devices/%s/speed", de->d_name))
+                goto the_end;
+            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 *opened = "husb: opened %s%s\n";
+    const char *fs_type[] = {"unknown", "proc", "dev", "sys"};
+    char devpath[PATH_MAX];
+
+    /* only check the host once */
+    if (!usb_fs_type) {
+        f = fopen(USBPROCBUS_PATH "/devices", "r");
+        if (f) {
+            /* devices found in /proc/bus/usb/ */
+            strcpy(devpath, USBPROCBUS_PATH);
+            usb_fs_type = USB_FS_PROC;
+            fclose(f);
+            dprintf(opened, USBPROCBUS_PATH, devices);
+        }
+        /* try additional methods if an access method hasn't been found yet */
+        f = fopen(USBDEVBUS_PATH "/devices", "r");
+        if (!usb_fs_type && f) {
+            /* devices found in /dev/bus/usb/ */
+            strcpy(devpath, USBDEVBUS_PATH);
+            usb_fs_type = USB_FS_DEV;
+            fclose(f);
+            dprintf(opened, USBDEVBUS_PATH, devices);
+        }
+        dir = opendir(USBSYSBUS_PATH "/devices");
+        if (!usb_fs_type && dir) {
+            /* devices found in /dev/bus/usb/ (yes - not a mistake!) */
+            strcpy(devpath, USBDEVBUS_PATH);
+            usb_fs_type = USB_FS_SYS;
+            closedir(dir);
+            dprintf(opened, USBSYSBUS_PATH, devices);
+        } else {
+            term_printf("husb: unable to access USB devices\n");
+            goto the_end;
+        }
+
+        /* 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 file-system with %s\n", fs_type[usb_fs_type], 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:
     return ret;
 }
 
-- 
1.5.4.3



^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [PATCH] Add USB sys file-system support (v8)
  2008-10-01 23:19                         ` [PATCH] Add USB sys file-system support (v8) TJ
@ 2008-10-07 20:09                           ` Anthony Liguori
  0 siblings, 0 replies; 20+ messages in thread
From: Anthony Liguori @ 2008-10-07 20:09 UTC (permalink / raw)
  To: TJ; +Cc: qemu-devel, kvm

TJ wrote:
> A bug crept into the version 7 patch whilst editing to help pass
> checkpatch.pl tests. Inadvertently, in moving an assignment out of an
> if() condition I replaced it with a test against the wrong variable.
> This is the corrected patch.
> ======
> Add USB sys file-system support
>
> 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 <linux@tjworld.net>
>   

Applied.  Thanks for keeping up with this patch.  I'm very happy with 
how it turned out.  One minor nit:

> +static int usb_host_scan(void *opaque, USBScanFunc *func)
> +{
> +    FILE *f = 0;
> +    DIR *dir = 0;
> +    int ret = 0;
> +    const char *devices = "/devices";
>   
> +    const char *opened = "husb: opened %s%s\n";
>   

When debug isn't enabled, these variables are unused and result in 
warnings (since they are only used in dprintf()).  Could you follow up 
with a patch that either stuck these variables in an #ifdef or 
refactored the code to make these warnings disappear?

Regards,

Anthony Liguori


^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2008-10-07 20:09 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-09-04 23:35 [PATCH] Add USB sys file-system support TJ
2008-09-05  2:06 ` [PATCH] Add USB sys file-system support (v2) TJ
2008-09-05 13:30   ` [Qemu-devel] " Jason Wessel
2008-09-05 18:51     ` TJ
2008-09-05 19:19       ` Jason Wessel
2008-09-05 20:28         ` TJ
2008-09-05 20:54           ` Jason Wessel
2008-09-05 21:13         ` [PATCH] Add USB sys file-system support (v3) TJ
2008-09-08 14:47           ` Jason Wessel
2008-09-17 19:31             ` [PATCH] Add USB sys file-system support (v4) TJ
2008-09-17 20:31               ` Anthony Liguori
2008-09-17 22:47                 ` [PATCH] Add USB sys file-system support (v5) TJ
2008-09-22 22:37                   ` Anthony Liguori
2008-09-23  1:23                     ` [Qemu-devel] " TJ
2008-09-23  1:33                     ` [PATCH] Add USB sys file-system support (v6) TJ
2008-09-25 17:45                       ` Anthony Liguori
2008-10-01 21:21                       ` [PATCH] Add USB sys file-system support (v7) TJ
2008-10-01 23:19                         ` [PATCH] Add USB sys file-system support (v8) TJ
2008-10-07 20:09                           ` Anthony Liguori
2008-09-05 19:20     ` [Qemu-devel] [PATCH] Add USB sys file-system support (v2) TJ

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).