Skip to contentSkip to conversation

USB driver conversion to use "struct device_driver"

RFC In review Greg KH 3 participants 8 messages Aug 10, 2002 – Aug 12, 2002 USB

lore
Share & tools
lore

Greg KH

author
#0 lore raw

RFC 1/1 USB driver conversion to use "struct device_driver"

Hi all,

Here's a patch against 2.5.30 that is the start of converting the USB code over to using the new core "struct device_driver" logic and functionality. Right now only the HUB and HID drivers are converted, and so they are the only ones that will work properly (the others will compile, but no devices are ever bound to them.)

The code is still quite rough in places, but the baic functions seem to work well (driver callbacks, etc.) There is some odd USB specific tweaks that were needed to be done in order to get this working properly.

The USB subsystem only binds drivers to USB "interfaces". A USB device may have many "interfaces", so a single device may have many drivers attached to it, handling different portions of it (think of a USB speaker, which has a audio driver for the audio stream, and a HID driver for the speaker buttons.) Because of this I had to create a "empty" device driver that I attach to the USB device structure. This ensures it shows up properly in the driverfs tree, and that no USB drivers try to bind to it.

Also, the driverfs representation of the USB devices has changed, possibly for the worse. Just try the patch to see what I mean :)

There is a known bug that happens in put_device() when a USB device is removed from the system, but the proper person already knows about it.

Comments?

If I don't hear any objections, I'll work on converting all of the USB drivers over to this model (the probe and disconnect function parameters have changed) and send the patch to Linus.

Many thanks to Pat Mochel for the original version of this patch (way back against 2.5.15) and for putting up with all of the USB device / interface madness.

thanks,

greg k-h

drivers/usb/core/config.c +3 -2
diff -Nru a/drivers/usb/core/config.c b/drivers/usb/core/config.c
@@ -89,7 +89,7 @@
 	return parsed;
 }
 
-static int usb_parse_interface(struct usb_interface *interface, unsigned char *buffer, int size)
+static int usb_parse_interface(struct usb_interface *interface, int ifnum, unsigned char *buffer, int size)
 {
 	int i, len, numskipped, retval, parsed = 0;
 	struct usb_descriptor_header *header;
@@ -99,6 +99,7 @@
 	interface->act_altsetting = 0;
 	interface->num_altsetting = 0;
 	interface->max_altsetting = USB_ALTSETTINGALLOC;
+	interface->ifnum = ifnum;
 
 	interface->altsetting = kmalloc(sizeof(struct usb_interface_descriptor) * interface->max_altsetting, GFP_KERNEL);
 	
@@ -323,7 +324,7 @@
 			}
 		}
 
-		retval = usb_parse_interface(config->interface + i, buffer, size);
+		retval = usb_parse_interface(config->interface + i, i, buffer, size);
 		if (retval < 0)
 			return retval;
 
drivers/usb/core/hcd.c +7 -5
diff -Nru a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
@@ -723,13 +723,15 @@
 {
 	int retval;
 
-	usb_dev->dev.parent = parent_dev;
-	strcpy (&usb_dev->dev.name[0], "usb_name");
-	strcpy (&usb_dev->dev.bus_id[0], "usb_bus");
-	retval = usb_new_device (usb_dev);
+//	usb_dev->dev.parent = parent_dev;
+//	strcpy (&usb_dev->dev.name[0], "usb_name");
+//	strcpy (&usb_dev->dev.bus_id[0], "usb_bus");
+	retval = usb_new_device (usb_dev, parent_dev);
 	if (retval)
-		put_device (&usb_dev->dev);
+		dbg("%s - retval = %d", __FUNCTION__, retval);
+//		put_device (&usb_dev->dev);
 	return retval;
+//	return usb_new_device (usb_dev, parent_dev);
 }
 EXPORT_SYMBOL (usb_register_root_hub);
 
drivers/usb/core/hcd.h +1 -1
diff -Nru a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
@@ -230,7 +230,7 @@
 /* -------------------------------------------------------------------------- */
 
 /* Enumeration is only for the hub driver, or HCD virtual root hubs */
-extern int usb_new_device(struct usb_device *dev);
+extern int usb_new_device(struct usb_device *dev, struct device *parent);
 extern void usb_connect(struct usb_device *dev);
 extern void usb_disconnect(struct usb_device **);
 
drivers/usb/core/hub.c +75 -66

255 lines not on this page · raw message

drivers/usb/core/hub.h +2 -1
diff -Nru a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h
@@ -166,7 +166,8 @@
 extern void usb_hub_tt_clear_buffer (struct usb_device *dev, int pipe);
 
 struct usb_hub {
-	struct usb_device	*dev;		/* the "real" device */
+//	struct usb_device	*dev;		/* the "real" device */
+	struct usb_interface	*intf;		/* the "real" device */
 	struct urb		*urb;		/* for interrupt polling pipe */
 
 	/* buffer for urb ... 1 bit each for hub and children, rounded up */
drivers/usb/core/usb.c +171 -11

233 lines not on this page · raw message

drivers/usb/input/hid-core.c +19 -16
diff -Nru a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
@@ -1338,9 +1338,10 @@
 	{ 0, 0 }
 };
 
-static struct hid_device *usb_hid_configure(struct usb_device *dev, int ifnum)
+static struct hid_device *usb_hid_configure(struct usb_interface *intf)
 {
-	struct usb_interface_descriptor *interface = dev->actconfig->interface[ifnum].altsetting + 0;
+	struct usb_interface_descriptor *interface = intf->altsetting + intf->act_altsetting;
+	struct usb_device *dev = intf->usb_device;
 	struct hid_descriptor *hdesc;
 	struct hid_device *hid;
 	unsigned quirks = 0, rsize = 0;
@@ -1450,7 +1451,7 @@
 		snprintf(hid->name, 128, "%04x:%04x", dev->descriptor.idVendor, dev->descriptor.idProduct);
 
 	usb_make_path(dev, buf, 64);
-	snprintf(hid->phys, 64, "%s/input%d", buf, ifnum);
+	snprintf(hid->phys, 64, "%s/input%d", buf, intf->ifnum);
 
 	if (usb_string(dev, dev->descriptor.iSerialNumber, hid->uniq, 64) <= 0)
 		hid->uniq[0] = 0;
@@ -1472,9 +1473,9 @@
 	return NULL;
 }
 
-static void hid_disconnect(struct usb_device *dev, void *ptr)
+static void hid_disconnect(struct usb_interface *intf)
 {
-	struct hid_device *hid = ptr;
+	struct hid_device *hid = intf->dev.driver_data;
 
 	usb_unlink_urb(hid->urbin);
 	usb_unlink_urb(hid->urbout);
@@ -1491,20 +1492,20 @@
 		usb_free_urb(hid->urbout);
 
 	hid_free_device(hid);
+	intf->dev.driver_data = NULL;
 }
 
-static void* hid_probe(struct usb_device *dev, unsigned int ifnum,
-		       const struct usb_device_id *id)
+static int hid_probe (struct usb_interface *intf)
 {
 	struct hid_device *hid;
 	char path[64];
 	int i;
 	char *c;
 
-	dbg("HID probe called for ifnum %d", ifnum);
+	dbg("HID probe called for ifnum %d", intf->ifnum);
 
-	if (!(hid = usb_hid_configure(dev, ifnum)))
-		return NULL;
+	if (!(hid = usb_hid_configure(intf)))
+		return -EIO;
 
 	hid_init_reports(hid);
 	hid_dump_device(hid);
@@ -1516,9 +1517,11 @@
 	if (!hiddev_connect(hid))
 		hid->claimed |= HID_CLAIMED_HIDDEV;
 
+	intf->dev.driver_data = hid;
+
 	if (!hid->claimed) {
-		hid_disconnect(dev, hid);
-		return NULL;
+		hid_disconnect(intf);
+		return -EIO;
 	}
 
 	printk(KERN_INFO);
@@ -1540,12 +1543,12 @@
 		}
 	}
 
-	usb_make_path(dev, path, 63);
+	usb_make_path(intf->usb_device, path, 63);
 
 	printk(": USB HID v%x.%02x %s [%s] on %s\n",
 		hid->version >> 8, hid->version & 0xff, c, hid->name, path);
 
-	return hid;
+	return 0;
 }
 
 static struct usb_device_id hid_usb_ids [] = {
@@ -1558,8 +1561,8 @@
 
 static struct usb_driver hid_driver = {
 	.name =		"hid",
-	.probe =	hid_probe,
-	.disconnect =	hid_disconnect,
+	.new_probe =	hid_probe,
+	.new_disco =	hid_disconnect,
 	.id_table =	hid_usb_ids,
 };
 
include/linux/usb.h +9 -1
diff -Nru a/include/linux/usb.h b/include/linux/usb.h
@@ -252,8 +252,10 @@
 	int act_altsetting;		/* active alternate setting */
 	int num_altsetting;		/* number of alternate settings */
 	int max_altsetting;		/* total memory allocated */
- 
+	int ifnum;			/* number of this interface */
+
 	struct usb_driver *driver;	/* driver */
+	struct usb_device *usb_device;	/* device this interface is on */
 	struct device dev;		/* interface specific device info */
 	void *private_data;
 };
@@ -683,6 +685,12 @@
 struct usb_driver {
 	struct module *owner;
 	const char *name;
+
+	int	(*new_probe)	(struct usb_interface *intf);
+	int	(*init)		(struct usb_interface *intf);
+	void	(*new_disco)	(struct usb_interface *intf);
+
+	struct device_driver driver;
 
 	void *(*probe)(
 	    struct usb_device *dev,		/* the device */
#1 lore raw

Am Samstag, 10. August 2002 02:10 schrieb Greg KH:

Quoted 10 lines

Hi all,

The USB subsystem only binds drivers to USB "interfaces". A USB device may have many "interfaces", so a single device may have many drivers attached to it, handling different portions of it (think of a USB speaker, which has a audio driver for the audio stream, and a HID driver for the speaker buttons.) Because of this I had to create a "empty" device driver that I attach to the USB device structure. This ensures it shows up properly in the driverfs tree, and that no USB drivers try to bind to it.

Hi,

the probe/disconnect changes are an improvement. But what do we call a device? IMHO the device in terms of driverfs is the interface, thus the usb_device should be seen as a bus, which interfaces are attached to.

Regards
Oliver

author
#2 lore raw
Quoted 12 lines · Oliver Neukum

Am Samstag, 10. August 2002 02:10 schrieb Greg KH:

Quoted 10 lines

Hi all,

The USB subsystem only binds drivers to USB "interfaces". A USB device may have many "interfaces", so a single device may have many drivers attached to it, handling different portions of it (think of a USB speaker, which has a audio driver for the audio stream, and a HID driver for the speaker buttons.) Because of this I had to create a "empty" device driver that I attach to the USB device structure. This ensures it shows up properly in the driverfs tree, and that no USB drivers try to bind to it.

Quoted 6 lines

Hi,

the probe/disconnect changes are an improvement. But what do we call a device? IMHO the device in terms of driverfs is the interface, thus the usb_device should be seen as a bus, which interfaces are attached to.

Hm, I don't really understand your question, but I'll try to explain how I did this.

Both struct usb_device and struct usb_interface now have a struct device. This is because _both_ things need to show up in the driverfs tree. I tried only making interfaces be devices (which is more of what the USB core code things of as devices), but the tree just didn't make much sense. Also, a USB device contains such things as the control pipe, and the usb descriptors and strings. So it is useful to show the device, as that's where you get the device name and serial number from :)

Does that help?

Try looking at the usb driverfs implementation as it is in 2.5.30, both the interfaces and the main device show up in the tree, I didn't change this. All this patch does is start to use "struct device_driver", and bind the drivers to the interfaces, _which_ is what the USB core has always done (no change in functionality here.) What this allows us to do is remove (eventually) the USB list of devices, and remove some other device list logic, as well as clean up the probe/disconnect interface.

thanks,

greg k-h

#3 lore raw
In reply to Greg KH

Good to start seeing "driver model" changes as well as just "driverfs" changes ...

Quoted 2 lines

Also, the driverfs representation of the USB devices has changed, possibly for the worse. Just try the patch to see what I mean :)

Why are devices children of the hub _interface_ now? Today they're children of the hub device. The hub spec requires only one interface for all hub devices, so it's safe the way it is today. With devices as children of hubs devices, things look more familiar ... hubs act like pci bridges (which they logically resemble).

Quoted 1 line

+static int usb_device_bind (struct device *dev, struct device_driver *drv)

Minor rough spot, please rename to usb_device_match() since it's the bus_type->match() callback. Might even be nice to split out some of the relevant code into "usb-device.c", mirroring what the "pci-device.c" code does but with bus-specific differences. There's too much random code in "usb.c" still for my taste! And all code at this level is usbcore-internal anyway, shouldn't be mixed with public driver APIs. :)

include/linux/usb.h line 696

Quoted 12 lines

struct usb_driver {

include/linux/usb.h +6 -0
 	struct module *owner;
 	const char *name;
+
+	int	(*new_probe)	(struct usb_interface *intf);
+	int	(*init)		(struct usb_interface *intf);
+	void	(*new_disco)	(struct usb_interface *intf);
+
+	struct device_driver driver;
 
 	void *(*probe)(
 	    struct usb_device *dev,		/* the device */

I don't see why this isn't done as a transparent wrapper around the existing probe()/disconnect() routines. PCI did this without any such major changes to the driver API, and I thought being able to do that was a (good!) device model design goal.

If we want to change the API to refocus on interfaces, rather than device plus whichever kind of identifying number is used in the relevant context, I'd rather start by getting rid of the APIs that have been problematic (device + number). That'd be nice for configurations and endpoints too, but I think most of those calls involve interfaces. Those changes would be a lot less invasive so far as device drivers are concerned.

Also, the generic driver model calls are probe/disconnect, suspend/resume, and release. Today, USB has probe/disconnect but not the others. I'd expect to see suspend/resume in there before a new init callback ... but I see the init routine is unused, maybe that just snuck in by accident.

- Dave

author
#4 lore raw
Quoted 5 lines · David Brownell

Why are devices children of the hub _interface_ now? Today they're children of the hub device. The hub spec requires only one interface for all hub devices, so it's safe the way it is today. With devices as children of hubs devices, things look more familiar ... hubs act like pci bridges (which they logically resemble).

Good point, I noticed that this had changed, but haven't fixed it, I'll make sure it goes back to the way it was before.

Quoted 7 lines

Minor rough spot, please rename to usb_device_match() since it's the bus_type->match() callback. Might even be nice to split out some of the relevant code into "usb-device.c", mirroring what the "pci-device.c" code does but with bus-specific differences. There's too much random code in "usb.c" still for my taste! And all code at this level is usbcore-internal anyway, shouldn't be mixed with public driver APIs. :)

The name will be changed, it's a hold over from when the driver model function was called "bind". And that's a good idea for a new file.

Quoted 10 lines
Quoted 10 lines
struct usb_driver {
	struct module *owner;
	const char *name;
include/linux/usb.h +6 -0
+
+	int	(*new_probe)	(struct usb_interface *intf);
+	int	(*init)		(struct usb_interface *intf);
+	void	(*new_disco)	(struct usb_interface *intf);
+
+	struct device_driver driver;
Quoted 7 lines
Quoted 2 lines
	void *(*probe)(
	    struct usb_device *dev,		/* the device */

I don't see why this isn't done as a transparent wrapper around the existing probe()/disconnect() routines. PCI did this without any such major changes to the driver API, and I thought being able to do that was a (good!) device model design goal.

I think making the probe() and disconnect() functions match the driver model makes more sense now. We have an easier time of fixing all of the USB drivers at once, compared to the PCI driver interface, which has _lots_ more drivers to convert.

Quoted 7 lines

If we want to change the API to refocus on interfaces, rather than device plus whichever kind of identifying number is used in the relevant context, I'd rather start by getting rid of the APIs that have been problematic (device + number). That'd be nice for configurations and endpoints too, but I think most of those calls involve interfaces. Those changes would be a lot less invasive so far as device drivers are concerned.

What APIs would those be?

Quoted 5 lines

Also, the generic driver model calls are probe/disconnect, suspend/resume, and release. Today, USB has probe/disconnect but not the others. I'd expect to see suspend/resume in there before a new init callback ... but I see the init routine is unused, maybe that just snuck in by accident.

Yes, the other callbacks will get added, and init() was added as part of the old original patch, I'll remove it.

thanks for the comments,

greg k-h

#5 lore raw
Quoted 4 lines
Quoted 1 line

Why are devices children of the hub _interface_ now?

Good point, I noticed that this had changed, but haven't fixed it, I'll make sure it goes back to the way it was before.

Thanks ... those paths were getting really atrocious!

The other thing I noticed about the tree structure was that the /drivers/bus/usb/devices directory has symlinks to both interfaces and devices. That's good for completeness, but the device links aren't very useful (and they really clutter up that directory, IMO, with two different kinds of object). Do they need to show up there?

We know "<interface>/.." always gives the USB device, so we don't really need such additional entries.

Quoted 19 lines
Quoted 10 lines
Quoted 10 lines
struct usb_driver {
	struct module *owner;
	const char *name;
include/linux/usb.h +6 -0
+
+	int	(*new_probe)	(struct usb_interface *intf);
+	int	(*init)		(struct usb_interface *intf);
+	void	(*new_disco)	(struct usb_interface *intf);
+
+	struct device_driver driver;
Quoted 7 lines
Quoted 2 lines
	void *(*probe)(
	    struct usb_device *dev,		/* the device */

I don't see why this isn't done as a transparent wrapper around the existing probe()/disconnect() routines. PCI did this without any such major changes to the driver API, and I thought being able to do that was a (good!) device model design goal.

Quoted 4 lines

I think making the probe() and disconnect() functions match the driver model makes more sense now. We have an easier time of fixing all of the USB drivers at once, compared to the PCI driver interface, which has _lots_ more drivers to convert.

Even so. This particular change also happens to make the usb_device_id->driver_data useless ... if the driver API changes, I'd need to see the MODULE_DEVICE_TABLE entry, or at least its driver_data, get passed too. That's a key level of bus-specific glue that the driver model doesn't explicitly acknowledge (seemingly expects to be handled transparently by the bus glue).

I guess I shouldn't be too sensitive about incompatible changes to the USB driver API, but in this case it bothers me a bit even though I do like the idea of making drivers think "correctly" (interface drivers, not device drivers).

Oh, and "new_disco" ... I thought "Disco is Dead"? :)

Quoted 10 lines
Quoted 7 lines

If we want to change the API to refocus on interfaces, rather than device plus whichever kind of identifying number is used in the relevant context, I'd rather start by getting rid of the APIs that have been problematic (device + number). That'd be nice for configurations and endpoints too, but I think most of those calls involve interfaces. Those changes would be a lot less invasive so far as device drivers are concerned.

What APIs would those be?

From a quick scan of <linux/usb.h>, I see these calls ... all of which would be less error prone if they just passed the relevant descriptor. (Errors happen when folk assume both two kinds of integer ID are the same... and it's also just confusing.) The interface->dev backlink you added is useful, and help get rid of the need for many of these:

  usb_set_configuration(struct usb_device *dev, int);
  usb_set_interface(struct usb_device *dev, int, int);

  usb_find_interface_driver_for_ifnum(struct usb_device *dev, int);
  usb_bind_driver(struct usb_driver *,struct usb_device *, int);
	// usb_unbind_driver takes interface handle already!!

usb_ifnum_to_ifpos(struct usb_device *dev, int);

  usb_ifnum_to_if(struct usb_device *dev, int);
	// basically, abolish the need for these calls
  usb_epnum_to_ep_desc(struct usb_device *dev, int);

Plus I'm strongly tempted to group all the "dev + pipe" calls the same way ... better to just pass the endpoint descriptor than to encode descriptor values as bitfields and then later waste time (repeateadly) tearing apart those bitfields.

Quoted 9 lines
Quoted 5 lines

Also, the generic driver model calls are probe/disconnect, suspend/resume, and release. Today, USB has probe/disconnect but not the others. I'd expect to see suspend/resume in there before a new init callback ... but I see the init routine is unused, maybe that just snuck in by accident.

Yes, the other callbacks will get added, and init() was added as part of the old original patch, I'll remove it.

I though that was what was going on!

Related issue to the suspend/resume code ... I recently noticed (again) that the hub code was disconnecting top-down rather than bottom up. That should eventually get delegated to the driver framework ... any idea whether there was a reason not to do that bottom-up in the first place? At what point does the driver model kick in to handle that part of what the hub driver now does? If the patch you sent around did that, my quick look missed it ... :)

- Dave

Quoted 4 lines

thanks for the comments,

greg k-h

author
#6 lore raw
Quoted 14 lines · David Brownell
Quoted 4 lines
Quoted 1 line

Why are devices children of the hub _interface_ now?

Good point, I noticed that this had changed, but haven't fixed it, I'll make sure it goes back to the way it was before.

Thanks ... those paths were getting really atrocious!

The other thing I noticed about the tree structure was that the /drivers/bus/usb/devices directory has symlinks to both interfaces and devices. That's good for completeness, but the device links aren't very useful (and they really clutter up that directory, IMO, with two different kinds of object). Do they need to show up there?

Quoted 2 lines

We know "<interface>/.." always gives the USB device, so we don't really need such additional entries.

Yeah, it is a bit ugly, and the whole symlink thing is going to be revisited. So for now I'm ignoring them, and hopefully Pat will decide on something later on :)

Quoted 7 lines

Even so. This particular change also happens to make the usb_device_id->driver_data useless ... if the driver API changes, I'd need to see the MODULE_DEVICE_TABLE entry, or at least its driver_data, get passed too. That's a key level of bus-specific glue that the driver model doesn't explicitly acknowledge (seemingly expects to be handled transparently by the bus glue).

Ugh, forgot about ->driver_info. Ok, I'll go work on that, pci gets around it by duplicating the "old" probe() interface. I don't want to throw away that info, as it is useful for some drivers.

Quoted 6 lines

I guess I shouldn't be too sensitive about incompatible changes to the USB driver API, but in this case it bothers me a bit even though I do like the idea of making drivers think "correctly" (interface drivers, not device drivers).

Oh, and "new_disco" ... I thought "Disco is Dead"? :)

"new_disco" will be dead, once all the drivers are converted :)

Quoted 21 lines
Quoted 1 line

What APIs would those be?

From a quick scan of <linux/usb.h>, I see these calls ... all of which would be less error prone if they just passed the relevant descriptor. (Errors happen when folk assume both two kinds of integer ID are the same... and it's also just confusing.) The interface->dev backlink you added is useful, and help get rid of the need for many of these:

  usb_set_configuration(struct usb_device *dev, int);
  usb_set_interface(struct usb_device *dev, int, int);

  usb_find_interface_driver_for_ifnum(struct usb_device *dev, int);
  usb_bind_driver(struct usb_driver *,struct usb_device *, int);
	// usb_unbind_driver takes interface handle already!!

usb_ifnum_to_ifpos(struct usb_device *dev, int);

  usb_ifnum_to_if(struct usb_device *dev, int);
	// basically, abolish the need for these calls
Quoted 6 lines
  usb_epnum_to_ep_desc(struct usb_device *dev, int);

Plus I'm strongly tempted to group all the "dev + pipe" calls the same way ... better to just pass the endpoint descriptor than to encode descriptor values as bitfields and then later waste time (repeateadly) tearing apart those bitfields.

Agreed, I'll look into fixing up the above functions, unless someone wants to send me a patch doing it first :)

Quoted 7 lines

Related issue to the suspend/resume code ... I recently noticed (again) that the hub code was disconnecting top-down rather than bottom up. That should eventually get delegated to the driver framework ... any idea whether there was a reason not to do that bottom-up in the first place? At what point does the driver model kick in to handle that part of what the hub driver now does? If the patch you sent around did that, my quick look missed it ... :)

Hm, I didn't realize it was going top-down at all. What changes caused that? And no, I don't think I changed it, as I didn't realize it had been changed in the first place :)

thanks,

greg k-h

#7 lore raw
Quoted 14 lines
Quoted 14 lines

usb_set_configuration(struct usb_device *dev, int); usb_set_interface(struct usb_device *dev, int, int);

usb_find_interface_driver_for_ifnum(struct usb_device *dev, int);

 usb_bind_driver(struct usb_driver *,struct usb_device *, int);
	// usb_unbind_driver takes interface handle already!!

usb_ifnum_to_ifpos(struct usb_device *dev, int);

 usb_ifnum_to_if(struct usb_device *dev, int);
	// basically, abolish the need for these calls

usb_epnum_to_ep_desc(struct usb_device *dev, int);

Quoted 8 lines
Quoted 4 lines

Plus I'm strongly tempted to group all the "dev + pipe" calls the same way ... better to just pass the endpoint descriptor than to encode descriptor values as bitfields and then later waste time (repeateadly) tearing apart those bitfields.

Agreed, I'll look into fixing up the above functions, unless someone wants to send me a patch doing it first :)

Maybe when Linus' release is a bit closer to the USB tree I could help with that. Right now it's sufficiently divergent to make usb patches against usbcore be rather helpful in general (though maybe not in that particular case). I'll certainly be glad to take a whack at that.

Quoted 9 lines
Quoted 7 lines

Related issue to the suspend/resume code ... I recently noticed (again) that the hub code was disconnecting top-down rather than bottom up. That should eventually get delegated to the driver framework ... any idea whether there was a reason not to do that bottom-up in the first place? At what point does the driver model kick in to handle that part of what the hub driver now does? If the patch you sent around did that, my quick look missed it ... :)

Quoted 3 lines

Hm, I didn't realize it was going top-down at all. What changes caused that? And no, I don't think I changed it, as I didn't realize it had been changed in the first place :)

I think it's just been that way for ages, no changes. It's actually usb_disconnect(), not the hub driver, that goes top down, disconnecting children only _after_ the parent is disconnected. (Might be nice to flag all devices as "dead" before disconnecting in such cases, but we don't have a way to flag devices as "dead" AFAIK. That'd make it easy to fail new urb submissions for now-gone devices.)

If the current changes don't automagically make disconnection work according to the device tree, something needs to change to make that work correctly. But I'm not sure what it'd be; seems like the converse of the probe() changes you started.

- Dave