From 13081c6915220db03886b177f1a8e0b2c63467c9 Mon Sep 17 00:00:00 2001 From: Scott Anderson Date: Fri, 6 Apr 2012 12:39:30 -0700 Subject: fastboot: Add ability to specify device path For manufacturing and testing, there is a need to talk to whatever device is connected to a given port on the host. This change modifies fastboot's "-s" option to take either a serial number or a device path. The device paths of the connected devices can be listed using "fastboot -l devices" whose output will resemble: 016B75D60A00600D usb:2-5 fastboot AD3C12020173 usb:1-4.3 fastboot The second column lists the device paths. If the -l option is not given, the output from "fastboot devices" will be the same as it used to be (i.e. the paths will not be printed). Finally, note that the format of the device paths are platform dependent. The example above is from Linux. On OS-X, the paths will be "usb:" followed by hex digits. For Windows, the device paths will be printed as "????????????" and the -s option will not be able to select a device until someone implements the underlying functionality in usb_windows.c. Change-Id: I1f01b8f47acd32edb0ac18db107316a2c923bbde Signed-off-by: Scott Anderson --- fastboot/usb_linux.c | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) (limited to 'fastboot/usb_linux.c') diff --git a/fastboot/usb_linux.c b/fastboot/usb_linux.c index 1ba87e6..19be51e 100644 --- a/fastboot/usb_linux.c +++ b/fastboot/usb_linux.c @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -108,6 +109,9 @@ static int filter_usb_device(int fd, char *ptr, int len, int writable, unsigned i; unsigned e; + struct stat st; + int result; + if(check(ptr, len, USB_DT_DEVICE, USB_DT_DEVICE_SIZE)) return -1; dev = (void*) ptr; @@ -132,7 +136,6 @@ static int filter_usb_device(int fd, char *ptr, int len, int writable, if (dev->iSerialNumber) { struct usbdevfs_ctrltransfer ctrl; __u16 buffer[128]; - int result; memset(buffer, 0, sizeof(buffer)); @@ -155,6 +158,42 @@ static int filter_usb_device(int fd, char *ptr, int len, int writable, } } + /* We need to get a path that represents a particular port on a particular + * hub. We are passed an fd that was obtained by opening an entry under + * /dev/bus/usb. Unfortunately, the names of those entries change each + * time devices are plugged and unplugged. So how to get a repeatable + * path? udevadm provided the inspiration. We can get the major and + * minor of the device file, read the symlink that can be found here: + * /sys/dev/char/: + * and then use the last element of that path. As a concrete example, I + * have an Android device at /dev/bus/usb/001/027 so working with bash: + * $ ls -l /dev/bus/usb/001/027 + * crw-rw-r-- 1 root plugdev 189, 26 Apr 9 11:03 /dev/bus/usb/001/027 + * $ ls -l /sys/dev/char/189:26 + * lrwxrwxrwx 1 root root 0 Apr 9 11:03 /sys/dev/char/189:26 -> + * ../../devices/pci0000:00/0000:00:1a.7/usb1/1-4/1-4.2/1-4.2.3 + * So our device_path would be 1-4.2.3 which says my device is connected + * to port 3 of a hub on port 2 of a hub on port 4 of bus 1 (per + * http://www.linux-usb.org/FAQ.html). + */ + info.device_path[0] = '\0'; + result = fstat(fd, &st); + if (!result && S_ISCHR(st.st_mode)) { + char cdev[128]; + char link[256]; + char *slash; + ssize_t link_len; + snprintf(cdev, sizeof(cdev), "/sys/dev/char/%d:%d", + major(st.st_rdev), minor(st.st_rdev)); + link_len = readlink(cdev, link, sizeof(link) - 1); + if (link_len > 0) { + link[link_len] = '\0'; + slash = strrchr(link, '/'); + if (slash) + snprintf(info.device_path, sizeof(info.device_path), "usb:%s", slash+1); + } + } + for(i = 0; i < cfg->bNumInterfaces; i++) { if(check(ptr, len, USB_DT_INTERFACE, USB_DT_INTERFACE_SIZE)) return -1; -- cgit v1.1