I've pretty much reached the end of the changes originally lined up for the hub driver, but there are two areas that still need attention: unbinding and error recovery. The problems and solutions aren't entirely well defined and some discussion might help clarify what needs to be done. There are several inter-related issues to consider.
The unbinding question is: How should the hub driver handle being unbound from a hub that is not unplugged? This can happen in several different ways involving user intervention via usbfs or sysfs. We could try to disallow such things for hubs, but it seems more robust to allow them and then handle them properly. If the hub driver is unbound, then the system won't be able to use the hub very well. In particular, connect changes won't be detected. On the other hand, devices that were plugged into the hub may still be electronically accessible. The cleanest way to handle this is to disable all the in-use ports and call usb_disconnect() for their children. However, it's a little questionable how we can do this. Once a driver's disconnect() is called, the driver isn't supposed to communicate with the device any more. By a quirk of the implementation we don't enforce this restriction for endpoint 0, which is all the hub driver needs for disabling all the ports. Relying on such quirks generally isn't a good idea, although this could reasonably be considered a special case. Of course, we can't disable the ports if the hub is suspended. I think the only way to deal with this complication is to check initially whether a device is suspended, and if it is, disallow unbinding or configuration changes. That's for all devices, not just hubs. As an additional complication, we _can't_ disallow unbinding when a driver is being unloaded. We have to let it unbind from its interface -- even though we won't be able to set the interface back to altsetting 0 afterwards. (Luckily this part of the problem doesn't affect the hub driver; it can't be unloaded unless all the usb_devices are already gone.) As a related matter, we also should disallow probing of interfaces on suspended devices. This won't be difficult, but it means a newly-loaded driver might not be able to bind to all the interfaces it should control. I think that's unavoidable. Now let's discuss error recovery. First, consider what sorts of errors might occur. One that the hub driver already checks for is 10 or more consecutive failures of the status interrupt URB (period is 256 ms). Another, highly critical sort of error (not currently handled) is failure of a hub to disable a port upon request. Finally, although not an error in the hub itself, is the possibility of rapid repeated cycling of the connection status of a port -- as might happen with a device that fails during initial probing, drops its connection, re-establishes it, and repeats... Errors of the first two sorts are best dealt with by resetting the hub. Should the user be given a chance to do something first? And if so, what could the user do? Unplugging the hub seems to be the only course of action, and that's even more drastic than resetting. The code that resets hubs for error recovery isn't working now; usb_reset_device() won't accept a hub as an argument. The issue, of course, is that when the hub is reset so are all its ports. Thus it's necessary to call usb_disconect() for all the child devices before resetting the hub. (In principle we could get around this. If there were an addition to the API for usb_drivers, a notification function for warning about impending resets, then we could simply notify all the children's drivers. But there isn't such an API, and it's not likely to arrive during 2.6.) It would be easy enough for usb_reset_device() to disconnect all the children when resetting a hub. Right now the code works the other way around: When the hub driver wants to reset a hub, it first disconnects the children and then calls usb_reset_device() (which will fail). Since device resets can arise from outside khubd (from usbfs, for instance), the order of function calls should be switched. (A related matter is the question of what it should mean to reset a root hub. It's not entirely clear what an HCD would need to do or whether the existing HCDs support the necessary functionality.) Then there's always the possibility that the reset will itself fail. The only ways this can happen are if the hub is suspended or unplugged, or if we can't determine which port it plugs into in the parent. That last possibility is a "This can't happen" sort of thing, so I will ignore it. Failing to reset a hub that is unplugged is understandable, of course. What about failure to reset a suspended hub? Fortunately I think this won't matter; if the hub is suspended there shouldn't be any need to reset it (but there's always the possibility of a reset request racing with usb_suspend). The remaining problem mentioned above is rapid repeated connect change events on a port, rather like init or inetd respawning a program too often. We can use the same approach they do, and stop handling connect change events when a port has too many of them in too short a time. For example, if there are 10 connect changes within a 30-second period, we could ignore that port for the next 10 minutes (and print a warning in the system log). This requires a certain amount of overhead -- memory space for a counter and a jiffies value for each port on each hub -- is it worthwhile? Alan Stern ------------------------------------------------------- This SF.Net email sponsored by Black Hat Briefings & Training. Attend Black Hat Briefings & Training, Las Vegas July 24-29 - digital self defense, top technical experts, no vendor pitches, unmatched networking opportunities. Visit www.blackhat.com _______________________________________________ [EMAIL PROTECTED] To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel