Upcoming changes It looks like certain changes are looming for the USB system, and I wanted to present a brief summary to make sure everyone knows about them and agrees they ought to be made. Simple ones first...
The halted[] member of struct usb_device is going to change to refuse[]. I posted another message about this a couple of weeks ago and nobody has responded, so I guess that's okay. Not surprising, since this feature is pretty much unused. The children[] and maxchild members will go away. They are meaningful only for hubs, and most of the information is already present in the driver model's children lists. The information missing in the driver model is the mapping from port number to child device. That mapping will be turned around; each struct usb_device will get a new member called portnum. The state member of struct usb_device will be explicitly _not_ under the protection of the serialize semaphore. Instead there will be a single global spinlock to protect all the states. Events like disconnection will be cause state to change as soon as they are detected, without having to wait for a driver to release usbdev->serialize. Now a more interesting item, not yet entirely certain: struct usb_device->serialize will become a read-write semaphore. The serialize semaphore protects against major changes, things that would involve binding/unbinding drivers or altering the device's physical state. In particular, the following routines will require the caller to hold the semaphore (or, in the new version, to have a write-lock): usb_driver_claim_interface, usb_driver_release_interface, usb_disconnect, usb_new_device, usb_disable_device, usb_reset_configuration, usb_set_configuration, usb_reset_device Also, a driver is guaranteed that the semaphore will be held when its probe() and disconnect() routines are called. In general, a driver can acquire the serialize semaphore whenever it wants to block one of the functions above temporarily. A good example would be when calling usb_ifnum_to_if(); that function scans the interfaces in the current configuration and the results would be meaningless if the configuration unexpectedly changed. There are some good reasons for making serialize into a read-write semaphore. Duncan Sands reports that the usbfs implementation would be greatly simplified. Also, if a device has multiple interfaces each with its own driver, then the separate drivers might individually want to prevent configuration changes without interfering with each other activities; getting a read-lock is the natural way to do this. Some longer-range changes: Add a new usb_device_state: USB_STATE_RESET. Although it doesn't correspond exactly to any state given in the USB spec it could be very useful. A device is in this state while it or a hub upstream from it is undergoing a reset. The somewhat obscure reason for having this is that it allows us to recover the devices attached to a hub when that hub is reset. Resetting a hub disables all its ports; after the hub revives, each of its children will have undergone the equivalent of a reset. Knowing that this has happened, we will be able to retain the child device structures and their driver bindings. They will resume activity rather than going through the process of logical disconnect followed by logical connect -- which would have the effect of replacing each device with a new incarnation, breaking things like filesystem mounts. This may turn out to be excessive design. I don't know that hubs need to be reset at all often, and it might not be worth the trouble to do all this. Furthermore, it would greatly complicate the set of possible state transitions in the hub driver. Add new callbacks to struct usb_driver to notify drivers that their device is about to be reset or has just finished a reset. I don't like the name "reset" for a callback as it implies that the driver should reset the device. Maybe better names would be "notify_reset" and "reinit" (or "notify_reinit"). As things stand now, we don't handle resets well. A device can have multiple drivers bound to multiple interfaces; when any one of them requests a reset it will affect all the others but they have no way to know what's going on. Likewise, if a hub is reset it automatically has the effect of resetting all the downstream devices, and the drivers need to know about it. The core will call notify_reset() for each driver bound to the device before performing the reset and will call reinit() afterwards, assuming the device survived the process intact. (If the device did not survive the core will call disconnect() instead.) Drivers will be able to suspend their activities, then reinitialize the device and resume where they left off. Although I described this as a long-range change, there's no reason it couldn't be implemented fairly soon. If a driver doesn't define a notify_reset or reinit callback pointer, the core simply won't notify it. That's exactly the same behavior we have now. Design patterns for USB drivers Many USB device drivers follow a design pattern that is typified by usb-skeleton. The driver has a per-device private data structure which includes an in-use semaphore and a refcount (or open_count). The semaphore serves to prevent the disconnect() routine from running while the driver is actively using the device. The refcount serves the usual purpose of preventing deallocation of the private structure until nothing is using it any more. With the new changes, another pattern might work better. In particular, there's no need for the private data structure to include an in-use semaphore since usbdev->serialize (read-locked) would do just as well. But in fact, the whole idea of using a semaphore to block disconnect() may be unnecessary. There has been a requirement that after a driver's disconnect() routine returns, the driver will not try to access the device at all -- all URBs must be unlinked and the struct usb_device may be deallocated at any time. The core is now (or soon will be) sufficiently well protected that this requirement is no longer needed. When disconnect() is called, usbdev->state will already have been set to USB_STATE_NOTATTACHED so no new URBs will be accepted, and all URBs in flight will have been unlinked. All the driver really needs to do is make sure that the struct usb_device isn't deallocated until it has finished cleaning up, and that can be handled with usb_get_dev()/usb_put_dev(). This approach does have the disadvantage of complicating the driver's exit routine. It would no longer be able to rely on the usb_deregister() call for synchronization; instead it would have to wait until all the private data structures had been freed. So perhaps it's not such a good idea. But it's worth considering, and it would speed up disconnect processing. Alan Stern ------------------------------------------------------- This SF.net email is sponsored by: Perforce Software. Perforce is the Fast Software Configuration Management System offering advanced branching capabilities and atomic changes on 50+ platforms. Free Eval! http://www.perforce.com/perforce/loadprog.html _______________________________________________ [EMAIL PROTECTED] To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel