dfu-util with USB physical location support

Werner Almesberger werner at openmoko.org
Sun Oct 7 11:07:21 CEST 2007


Hi Harald,

I've now extended u-boot to accept physical device paths as a
selection criteron. Usage:

dfu-util -p 1+0+2

This would select bus 1, then port 0 of the root hub, and then
port 2 of the hub placed there.

Prerequisite: libusbpath must be installed. To ease transition,
I've made the use of libusbpath conditional for now.

To determine the path to a device, do this:

- lsusb   to find out bus and device number
- usbpath bus/devnum   to translate this to a path

E.g.,
# lsusb
...
Bus 001 Device 025: ID 1457:511a  
...
# usbpath 1/25
1+0
# dfu-util -p 1+0 ...

usbpath (which also provides libusbpath) is in
http://svn.openmoko.org/trunk/src/host/usbpath/

svn diff is attached. Since the search logic has now gotten more
complex, I've merged the almost identical code of
get_first_dfu_device and count_dfu_devices into a new function
iterate_dfu_devices that uses a callback to decide what to do.

Okay to commit ?

- Werner
-------------- next part --------------
Index: configure.ac
===================================================================
--- configure.ac	(revision 3091)
+++ configure.ac	(working copy)
@@ -17,12 +17,14 @@
 
 PKG_CHECK_MODULES(USB, libusb >= 0.1.4,,
                  AC_MSG_ERROR([*** Required libusb >= 0.1.4 not installed ***]))
+AC_CHECK_LIB([usbpath],[usb_path2devnum],,,-lusb)
+
 LIBS="$LIBS $USB_LIBS"
 CFLAGS="$CFLAGS $USB_CFLAGS"
 
 # Checks for header files.
 AC_HEADER_STDC
-AC_CHECK_HEADERS([stdlib.h string.h stdio.h])
+AC_CHECK_HEADERS([stdlib.h string.h stdio.h usbpath.h])
 
 # Checks for typedefs, structures, and compiler characteristics.
 AC_C_CONST
Index: src/main.c
===================================================================
--- src/main.c	(revision 3093)
+++ src/main.c	(working copy)
@@ -37,7 +37,11 @@
 #include "config.h"
 #endif
 
+#ifdef HAVE_USBPATH_H
+#include <usbpath.h>
+#endif
 
+
 int debug;
 static int verbose = 0;
 
@@ -47,6 +51,8 @@
 #define DFU_IFF_CONFIG		0x0400
 #define DFU_IFF_IFACE		0x0800
 #define DFU_IFF_ALT		0x1000
+#define DFU_IFF_DEVNUM		0x2000
+#define DFU_IFF_PATH		0x4000
 
 struct usb_vendprod {
 	u_int16_t vendor;
@@ -59,6 +65,9 @@
 	u_int8_t configuration;
 	u_int8_t interface;
 	u_int8_t altsetting;
+	int bus;
+	u_int8_t devnum;
+	const char *path;
 	unsigned int flags;
 	struct usb_device *dev;
 
@@ -211,53 +220,74 @@
 	return num_found;
 }
 
-/* Find the first DFU-capable device, save it in dfu_if->dev */
-static int get_first_dfu_device(struct dfu_if *dif)
+
+/* Iterate over all matching DFU capable devices within system */
+static int iterate_dfu_devices(struct dfu_if *dif,
+    int (*action)(struct usb_device *dev, void *user), void *user)
 {
 	struct usb_bus *usb_bus;
 	struct usb_device *dev;
 
+	/* Walk the tree and find our device. */
 	for (usb_bus = usb_get_busses(); NULL != usb_bus;
 	     usb_bus = usb_bus->next) {
 		for (dev = usb_bus->devices; NULL != dev; dev = dev->next) {
-			if (!dif || 
-			    (dif->flags & (DFU_IFF_VENDOR|DFU_IFF_PRODUCT)) == 0 ||
-			    (dev->descriptor.idVendor == dif->vendor &&
-			     dev->descriptor.idProduct == dif->product)) {
-			     	if (count_dfu_interfaces(dev) >= 1) {
-					dif->dev = dev;
-					return 1;
-				}
-			}
+			int retval;
+
+			if (dif && (dif->flags &
+			    (DFU_IFF_VENDOR|DFU_IFF_PRODUCT)) &&
+		    	    (dev->descriptor.idVendor != dif->vendor ||
+		     	    dev->descriptor.idProduct != dif->product))
+				continue;
+			if (dif && (dif->flags & DFU_IFF_DEVNUM) &&
+		    	    (atoi(usb_bus->dirname) != dif->bus ||
+		     	    dev->devnum != dif->devnum))
+				continue;
+
+			retval = action(dev, user);
+			if (retval)
+				return retval;
 		}
 	}
+	return 0;
+}
 
+
+static int found_dfu_device(struct usb_device *dev, void *user)
+{
+	struct dfu_if *dif = user;
+
+	dif->dev = dev;
+	return 1;
+}
+
+
+/* Find the first DFU-capable device, save it in dfu_if->dev */
+static int get_first_dfu_device(struct dfu_if *dif)
+{
+	return iterate_dfu_devices(dif, found_dfu_device, dif);
+}
+
+
+static int count_one_dfu_device(struct usb_device *dev, void *user)
+{
+	int *num = user;
+
+	(*num)++;
 	return 0;
 }
 
+
 /* Count DFU capable devices within system */
 static int count_dfu_devices(struct dfu_if *dif)
 {
-	struct usb_bus *usb_bus;
-	struct usb_device *dev;
 	int num_found = 0;
 
-	/* Walk the tree and find our device. */
-	for (usb_bus = usb_get_busses(); NULL != usb_bus;
-	     usb_bus = usb_bus->next) {
-		for (dev = usb_bus->devices; NULL != dev; dev = dev->next) {
-			if (!dif || 
-			    (dif->flags & (DFU_IFF_VENDOR|DFU_IFF_PRODUCT)) == 0 ||
-			    (dev->descriptor.idVendor == dif->vendor &&
-			     dev->descriptor.idProduct == dif->product)) {
-				if (count_dfu_interfaces(dev) >= 1)
-					num_found++;
-			}
-		}
-	}
+	iterate_dfu_devices(dif, count_one_dfu_device, &num_found);
 	return num_found;
 }
 
+
 static int list_dfu_interfaces(void)
 {
 	struct usb_bus *usb_bus;
@@ -294,6 +324,40 @@
 	return 0;
 }
 
+
+#ifdef HAVE_USBPATH_H
+
+static int resolve_device_path(struct dfu_if *dif)
+{
+	int res;
+
+	if (!(dif->flags & DFU_IFF_PATH))
+		return 0;
+
+	res = usb_path2devnum(dif->path);
+	if (res < 0)
+		return -EINVAL;
+	if (!res)
+		return 0;
+
+	dif->bus = atoi(dif->path);
+	dif->devnum = res;
+	dif->flags |= DFU_IFF_DEVNUM;
+	return res;
+}
+
+#else /* HAVE_USBPATH_H */
+
+static int resolve_device_path(struct dfu_if *dif)
+{
+	fprintf(stderr,
+	    "USB device paths are not supported by this dfu-util.\n");
+	exit(1);
+}
+
+#endif /* !HAVE_USBPATH_H */
+
+
 static void help(void)
 {
 	printf("Usage: dfu-util [options] ...\n"
@@ -301,6 +365,7 @@
 		"  -V --version\t\t\tPrint the version number\n"
 		"  -l --list\t\t\tList the currently attached DFU capable USB devices\n"
 		"  -d --device vendor:product\tSpecify Vendor/Product ID of DFU device\n"
+		"  -p --devnum bus+port+...\tSpecify path to DFU device\n"
 		"  -c --cfg config_nr\t\tSpecify the Configuration of DFU device\n"
 		"  -i --intf intf_nr\t\tSpecify the DFU Interface number\n"
 		"  -a --alt alt\t\t\tSpecify the Altsetting of the DFU Interface\n"
@@ -323,6 +388,7 @@
 	{ "verbose", 0, 0, 'v' },
 	{ "list", 0, 0, 'l' },
 	{ "device", 1, 0, 'd' },
+	{ "path", 1, 0, 'p' },
 	{ "configuration", 1, 0, 'c' },
 	{ "cfg", 1, 0, 'c' },
 	{ "interface", 1, 0, 'i' },
@@ -370,7 +436,7 @@
 
 	while (1) {
 		int c, option_index = 0;
-		c = getopt_long(argc, argv, "hVvld:c:i:a:t:U:D:R", opts, &option_index);
+		c = getopt_long(argc, argv, "hVvld:p:c:i:a:t:U:D:R", opts, &option_index);
 		if (c == -1)
 			break;
 
@@ -400,6 +466,21 @@
 			dif->product = vendprod.product;
 			dif->flags |= (DFU_IFF_VENDOR | DFU_IFF_PRODUCT);
 			break;
+		case 'p':
+			/* Parse device path */
+			dif->path = optarg;
+			dif->flags |= DFU_IFF_PATH;
+			ret = resolve_device_path(dif);
+			if (ret < 0) {
+				fprintf(stderr, "unable to parse `%s'\n",
+				    optarg);
+				exit(2);
+			}
+			if (!ret) {
+				fprintf(stderr, "cannot find `%s'\n", optarg);
+				exit(1);
+			}
+			break;
 		case 'c':
 			/* Configuration */
 			dif->configuration = atoi(optarg);
@@ -535,6 +616,18 @@
 		if (usb_find_devices() < 2)
 			printf("not at least 2 device changes found ?!?\n");
 
+		ret = resolve_device_path(dif);
+		if (ret < 0) {
+			fprintf(stderr,
+			    "internal error: cannot re-parse `%s'\n",
+			    dif->path);
+			abort();
+		}
+		if (!ret) {
+			fprintf(stderr, "Can't resolve path after RESET?\n");
+			exit(1);
+		}
+
 		num_devs = count_dfu_devices(dif);
 		if (num_devs == 0) {
 			fprintf(stderr, "Lost device after RESET?\n");


More information about the openmoko-uboot mailing list