From: TJ <linux@tjworld.net>
To: qemu-devel@nongnu.org
Cc: kvm <kvm@vger.kernel.org>
Subject: [PATCH] Add USB sys file-system support (v5)
Date: Wed, 17 Sep 2008 23:47:27 +0100 [thread overview]
Message-ID: <1221691647.17792.55.camel@hephaestion> (raw)
In-Reply-To: <48D16904.30104@codemonkey.ws>
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;
}
next prev parent reply other threads:[~2008-09-17 22:47 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
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 ` TJ [this message]
2008-09-22 22:37 ` [PATCH] Add USB sys file-system support (v5) 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
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1221691647.17792.55.camel@hephaestion \
--to=linux@tjworld.net \
--cc=kvm@vger.kernel.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.