On Tue, 9 Dec 2003, Alan Stern wrote: > Simply stated, things that matter to a device driver can thereby be of > interest to the core. If by providing a simple -- though not strictly > necessary -- service the core can make device drivers easier to write and > more obviously error-free, then the core should provide it.
In case that wasn't clear enough, consider this rhetorical question: Why does the core contain usb_ifnum_to_if()? It's a simple routine; any driver that needs it could easily include its own version. Answer: It performs a useful task that would otherwise require duplicating code. It avoids a common mistaken assumption (that interfaces are stored in numerical order starting from 0). It makes it easier for drivers to do something useful and do it correctly. It's for exactly these same reasons that I think the core should facilitate waiting for URBs to be idle. > > Curious -- I just posted a patch that tests whether the urb is on the > > queue. Mostly since looking at the AIO code reminded me that'd be a > > good idea, so I updated the gadget controller drivers to do that on > > their unlink paths and finally sent in the host-side version. That's > > what you said we "have no way of doing", right? > > Yeah. Although I'm aware of the existence of the urb_list stuff, it > hasn't really sunken in. And I notice that it is protected by a spinlock. > Does this mean that your two states correspond formally to an URB being on > or off the dev->urb_list? I take that back. After thinking some more, it became clear that the urb_list test does _not_ detect whether the URB is linked. Part of the problem is that I don't remember what precise definition you were using for what it means for an URB to be linked. Here's my definition, an operational one: An URB is linked when the low-level HC driver thinks it is. This can be made a little clearer through the following considerations. In any HC driver there must be two points in the code, one on the submit path, the other on the dequeue path, presumably protected by the same spinlock. Let's call them point A and point B. In a race between submit_urb and unlink_urb, the result is decided by which point is reached first. If the submit thread reaches A before the unlink thread reaches B, then the URB will get linked and then unlinked. If the unlink thread reaches B before the submit thread reaches A, then the unlink will fail (because the URB wasn't linked to begin with) and the link will succeed -- so the URB will end up being linked. I can tell you exactly where these two points are in the UHCI driver; no doubt you know where they are in OHCI and EHCI. In short, whether an URB is linked has nothing to do with whether it's on the urb_list. All that matters is whether the HC driver successfully passed through point A. If usb_unlink_urb() thinks differently then it is buggy. (And just to prevent some kibitzer from picking on a loose end, of course the URB stops being linked when the HC driver calls giveback_urb.) Consider this proposal for an addition (not a change!) to the existing API. Let's define 3 new bits in urb->flags: URB_LINKED, URB_COMPLETING, and URB_INVALID (maybe someone can come up with a better name than that last one). URB_LINKED will be set by the HCD precisely at the time the URB is linked. URB_COMPLETING will be set by the core during the time the URB's completion handler is running. (And the core will carefully set URB_COMPLETING in giveback_urb before or at exactly the same time as clearing URB_LINKED.) Then usb_wait_for_urb() becomes a simple wait loop, polling for (urb->flags & (URB_LINKED | URB_COMPLETING)) == 0 Very simple, easily seen to be precise and correct. The third flag is to help drivers avoid the need for locking synchronization to prevent resubmission. The idea is very simple: If the URB_INVALID flag is set, a low-level HC driver will refuse to link the URB. This test _must_ be made within the same spinlock-protected region that contains point A, so that it is sufficiently atomic with respect to submission and unlinking. With these mechanisms available, a driver can safely stop an URB from being resubmitted and wait for it to be idle as follows: urb->flags |= URB_INVALID; usb_unlink_urb(&urb); // Asynchronous unlink usb_wait_for_urb(&urb); urb->flags &= ~URB_INVALID; No locking is needed in the driver; the core takes of it automatically. When this sequence completes, the URB is guaranteed not to be linked and the completion handler is guaranteed not to be running. Even if it always resubmits. (Although it is necessary that the handler does not clear urb->flags!) The URB can safely be reused or the driver module unloaded. The sequence above could be bundled up into a single subroutine that would essentially replace the current synchronous unlink_urb. It wouldn't do the same thing, but it would do what the drivers want. To implement this requires very minimal changes in the core and the HC drivers. If anyone would like to see a patch, I'll work one up. Alan Stern ------------------------------------------------------- This SF.net email is sponsored by: IBM Linux Tutorials. Become an expert in LINUX or just sharpen your skills. Sign up for IBM's Free Linux Tutorials. Learn everything from the bash shell to sys admin. Click now! http://ads.osdn.com/?ad_id=1278&alloc_id=3371&op=click _______________________________________________ [EMAIL PROTECTED] To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel