bk://kernel.bkbits.net/gregkh/linux/usb-2.6 stern@rowland.harvard.edu|ChangeSet|20040423234130|34087 stern # This is a BitKeeper generated diff -Nru style patch. # # ChangeSet # 2004/04/25 23:06:05-07:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb # # include/linux/pci_ids.h # 2004/04/25 23:06:02-07:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/04/24 23:51:05-07:00 akpm@bix.(none) # Merge bk://kernel.bkbits.net/gregkh/linux/usb-2.6 # into bix.(none):/usr/src/bk-usb # # drivers/usb/core/usb.c # 2004/04/24 23:51:02-07:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/04/23 16:41:30-07:00 stern@rowland.harvard.edu # [PATCH] USB: Altsetting update for USB net drivers # # The only driver under usb/net that needed any altsetting changes was # usbnet. I'm not looking forward to going through all the source files # under usb/serial. :-( # # drivers/usb/net/usbnet.c # 2004/04/22 09:56:28-07:00 stern@rowland.harvard.edu +4 -4 # USB: Altsetting update for USB net drivers # # ChangeSet # 2004/04/23 16:41:04-07:00 stern@rowland.harvard.edu # [PATCH] USB: Altsetting update for USB misc drivers # # This is the altsetting update for the drivers under usb/misc. As you can, # not much was needed at all. # # drivers/usb/misc/uss720.c # 2004/04/22 09:08:37-07:00 stern@rowland.harvard.edu +1 -1 # USB: Altsetting update for USB misc drivers # # drivers/usb/misc/legousbtower.c # 2004/04/22 09:01:26-07:00 stern@rowland.harvard.edu +1 -1 # USB: Altsetting update for USB misc drivers # # ChangeSet # 2004/04/23 16:40:35-07:00 stern@rowland.harvard.edu # [PATCH] USB: Altsetting updates for USB media drivers # # This patch implements the new altsetting regime for the drivers under # usb/media. Not much needed to be changed. I'm unable to test any of the # changes, but at least they compile all right (except that I didn't even # try to compile the pwc driver since it's marked BROKEN). # # The stv680 and w9968cf drivers still include an assumption that they are # bound to interface number 0. Since that the drivers are fairly tightly # linked to a specific kind of device I didn't try to change those # assumptions, but maybe they should be changed. # # drivers/usb/media/vicam.c # 2004/04/22 04:41:49-07:00 stern@rowland.harvard.edu +1 -1 # USB: Altsetting updates for USB media drivers # # drivers/usb/media/ultracam.c # 2004/04/21 09:26:45-07:00 stern@rowland.harvard.edu +4 -3 # USB: Altsetting updates for USB media drivers # # drivers/usb/media/se401.c # 2004/04/21 09:21:19-07:00 stern@rowland.harvard.edu +1 -1 # USB: Altsetting updates for USB media drivers # # drivers/usb/media/pwc-if.c # 2004/04/21 09:18:47-07:00 stern@rowland.harvard.edu +5 -2 # USB: Altsetting updates for USB media drivers # # drivers/usb/media/ov511.c # 2004/04/22 04:40:56-07:00 stern@rowland.harvard.edu +11 -3 # USB: Altsetting updates for USB media drivers # # drivers/usb/media/konicawc.c # 2004/04/21 09:41:57-07:00 stern@rowland.harvard.edu +12 -5 # USB: Altsetting updates for USB media drivers # # drivers/usb/media/ibmcam.c # 2004/04/21 09:32:00-07:00 stern@rowland.harvard.edu +5 -4 # USB: Altsetting updates for USB media drivers # # ChangeSet # 2004/04/23 16:40:06-07:00 stern@rowland.harvard.edu # [PATCH] USB: Cosmetic improvements for the UHCI driver # # This patch makes a few minor improvements to the appearance of the UHCI # driver. Please apply. # # drivers/usb/host/uhci-hcd.h # 2004/04/19 04:05:56-07:00 stern@rowland.harvard.edu +7 -7 # USB: Cosmetic improvements for the UHCI driver # # drivers/usb/host/uhci-hcd.c # 2004/04/14 03:19:54-07:00 stern@rowland.harvard.edu +10 -10 # USB: Cosmetic improvements for the UHCI driver # # ChangeSet # 2004/04/23 16:39:38-07:00 stern@rowland.harvard.edu # [PATCH] USB: Ignore URB_NO_INTERRUPT flag in UHCI # # Following a suggestion of David Brownell's I have decided to remove # support for the URB_NO_INTERRUPT flag in the UHCI driver. The overall # effect of the flag is to reduce the number of interrupts, thereby # improving throughput somewhat while increasing the duration of the # remaining IRQ handlers quite a lot (i.e., increasing interrupt variance). # So I think we're better off without it. Mind you, this is all in the # absence of any firm measurements. # # A common case where this will come up is during usb-storage bulk # transfers. Such transfers are generally divided into scatter-gather # components each corresponding to a single URB and transferring one memory # page (4 KB). While generating an interrupt for each one is a little # faster than ideal -- about every 3 ms -- it's better than waiting until 64 # KB has been transferred and there are 1024 individual TDs to clean up # during the IRQ. # # drivers/usb/host/uhci-hcd.c # 2004/04/16 04:02:37-07:00 stern@rowland.harvard.edu +7 -3 # USB: Ignore URB_NO_INTERRUPT flag in UHCI # # ChangeSet # 2004/04/23 16:20:26-07:00 baldrick@free.fr # [PATCH] USB usbfs: drop pointless racy check # # The check of interface->dev.driver requires a lock to be taken # to protect against driver binding changes. But in fact I think it # is better just to drop the test. The result is that the caller is # required to claim an interface before changing the altsetting, # which is consistent with the other routines that operate on # interfaces. # # devio.c | 6 ++---- # 1 files changed, 2 insertions(+), 4 deletions(-) # # drivers/usb/core/devio.c # 2004/04/14 05:18:37-07:00 baldrick@free.fr +2 -4 # USB usbfs: drop pointless racy check # # ChangeSet # 2004/04/23 16:20:07-07:00 baldrick@free.fr # [PATCH] USB usbfs: missing lock in proc_getdriver # # Hi Oliver, # # > I expect it to rarely matter, but it might matter now and then. It's # > just a question of hygiene. If you are using a temporary buffer I'd # > like to see it used to full advantage. So either drop the lock or do # > a direct copy. I'd prefer the first option your patch implemented. # # I agree. Greg, please consider applying the updated patch: # # # # Protect against driver binding changes while reading the driver name. # # drivers/usb/core/devio.c # 2004/04/14 07:03:12-07:00 baldrick@free.fr +6 -4 # USB usbfs: missing lock in proc_getdriver # # ChangeSet # 2004/04/23 16:19:43-07:00 baldrick@free.fr # [PATCH] USB usbfs: destroy submitted urbs only on the disconnected interface # # The remaining three patches contain miscellaneous fixes to usbfs. # This one fixes up the disconnect callback to only shoot down urbs # on the disconnected interface, and not on all interfaces. It also adds # a sanity check (this check is pointless because the interface could # never have been claimed in the first place if it failed, but I feel better # having it there). # # devio.c | 6 ++++-- # 1 files changed, 4 insertions(+), 2 deletions(-) # # drivers/usb/core/devio.c # 2004/04/14 05:18:20-07:00 baldrick@free.fr +4 -2 # USB usbfs: destroy submitted urbs only on the disconnected interface # # ChangeSet # 2004/04/23 16:19:14-07:00 baldrick@free.fr # [PATCH] USB usbfs: fix up releaseintf # # The semaphore is now taken in the callers. # # devio.c | 2 -- # 1 files changed, 2 deletions(-) # # drivers/usb/core/devio.c # 2004/04/14 05:18:08-07:00 baldrick@free.fr +0 -2 # USB usbfs: fix up releaseintf # # ChangeSet # 2004/04/23 16:18:50-07:00 baldrick@free.fr # [PATCH] USB usbfs: fix up proc_ioctl # # The semaphore is now taken in the caller. # # devio.c | 2 -- # 1 files changed, 2 deletions(-) # # drivers/usb/core/devio.c # 2004/04/14 05:17:56-07:00 baldrick@free.fr +0 -2 # USB usbfs: fix up proc_ioctl # # ChangeSet # 2004/04/23 16:18:24-07:00 baldrick@free.fr # [PATCH] USB usbfs: fix up proc_setconfig # # The semaphore is now taken in the caller. # # devio.c | 2 -- # 1 files changed, 2 deletions(-) # # drivers/usb/core/devio.c # 2004/04/14 05:17:46-07:00 baldrick@free.fr +0 -2 # USB usbfs: fix up proc_setconfig # # ChangeSet # 2004/04/23 16:17:59-07:00 baldrick@free.fr # [PATCH] USB usbfs: remove obsolete comment from proc_resetdevice # # devio.c | 3 --- # 1 files changed, 3 deletions(-) # # drivers/usb/core/devio.c # 2004/04/14 05:17:37-07:00 baldrick@free.fr +0 -3 # USB usbfs: remove obsolete comment from proc_resetdevice # # ChangeSet # 2004/04/23 16:17:35-07:00 baldrick@free.fr # [PATCH] USB usbfs: replace the per-file semaphore with the per-device semaphore # # devio.c | 43 +++++++++++++++++++++++-------------------- # usbdevice_fs.h | 1 - # 2 files changed, 23 insertions(+), 21 deletions(-) # # include/linux/usbdevice_fs.h # 2004/04/14 05:34:00-07:00 baldrick@free.fr +0 -1 # USB usbfs: replace the per-file semaphore with the per-device semaphore # # drivers/usb/core/devio.c # 2004/04/14 05:17:29-07:00 baldrick@free.fr +23 -20 # USB usbfs: replace the per-file semaphore with the per-device semaphore # # ChangeSet # 2004/04/23 16:17:09-07:00 baldrick@free.fr # [PATCH] USB usbfs: take a reference to the usb device # # Hi Greg, this is the first of a series of patches that replace the # per-file semaphore ps->devsem with the per-device semaphore # ps->dev->serialize. The role of devsem was to protect against # device disconnection. This can be done equally well using # ps->dev->serialize. On the other hand, ps->dev->serialize # protects against configuration and other changes, and has # already been introduced into usbfs in several places. Using # just one semaphore simplifies the code and removes some # remaining race conditions. It should also fix the oopses some # people have been seeing. In this first patch, a reference is # taken to the usb device as long as the usbfs file is open. That # way we can use ps->dev->serialize for as long as ps exists. # # devio.c | 27 ++++++++++++++++----------- # inode.c | 3 --- # 2 files changed, 16 insertions(+), 14 deletions(-) # # drivers/usb/core/inode.c # 2004/04/14 05:15:29-07:00 baldrick@free.fr +0 -3 # USB usbfs: take a reference to the usb device # # drivers/usb/core/devio.c # 2004/04/14 05:15:29-07:00 baldrick@free.fr +16 -11 # USB usbfs: take a reference to the usb device # # ChangeSet # 2004/04/23 15:45:24-07:00 david-b@pacbell.net # [PATCH] USB: khubd fixes # # This goes on top of the other enumeration patch I just sent, # to handle some dubious and/or broken hub configurations better. # # # Make khubd handle some cases better: # # - Track power budget for bus-powered hubs. This version only warns # when the budgets are exceeded. Eventually, the budgets should help # prevent such errors. # # - Rejects illegal USB setup: two consecutive bus powered hubs # would exceed the voltage drop budget, causing much flakiness. # # - For hosts with high speed hubs, warn when devices are hooked up # to full speed hubs if they'd be faster on a high speed one. # # - For hubs that don't do power switching, don't try to use it # # - For hubs that aren't self-powered, don't report local power status # # drivers/usb/core/hub.h # 2004/04/19 08:29:02-07:00 david-b@pacbell.net +2 -0 # USB: khubd fixes # # drivers/usb/core/hub.c # 2004/04/20 20:44:45-07:00 david-b@pacbell.net +143 -15 # USB: khubd fixes # # ChangeSet # 2004/04/23 15:44:57-07:00 david-b@pacbell.net # [PATCH] USB: re-factor enumeration logic # # This is an update to some patches from the December/January # timeframe, which will help sort out some of the mess for # drivers that need to use the reset logic. It's one of the # last significant patches in my gadget-2.6 tree that haven't # yet been merged into the main kernel tree. # # # More refactoring of the enumeration code paths: # # * The first half of usb_new_device() becomes the second half of a new # hub_port_init() routine (resets, sets address, gets descriptor) # # * The middle chunk of hub_port_connect_change() becomes the first half # of that new hub_port_init() routine. # # * Khubd uses that new routine in hub_port_connect_change(). # # * Now usb_new_device() cleans up better after faults, and has # a more useful locking policy (caller owns dev->serialize). # # * Has related minor cleanups including commenting some of # the curious request sequences coming from khubd. # # Refactoring means a lot of the current usb_reset_device() logic won't # need to stay an imperfect clone of the enumeration code ... soon, it # can just call hub_port_init(). # # Even without touching usb_reset_device(), this eliminates a deadlock. # Previously, address0_sem was used both during probe and during reset, # so probe routines can't implement DFU firmware download (involves a # reset; DFU also uncovers other problems) or safely recover from probe # faults by resetting (usb-storage can try that). Now that lock is no # longer held during probe(); so those deadlocks are gone. (And some # drivers, like at76c503, can start to remove ugly workarounds.) # # drivers/usb/core/usb.c # 2004/04/21 03:46:29-07:00 david-b@pacbell.net +13 -79 # USB: re-factor enumeration logic # # drivers/usb/core/hub.c # 2004/04/21 03:46:29-07:00 david-b@pacbell.net +215 -72 # USB: re-factor enumeration logic # # drivers/usb/core/hcd.c # 2004/04/21 03:46:29-07:00 david-b@pacbell.net +12 -0 # USB: re-factor enumeration logic # # ChangeSet # 2004/04/23 15:44:32-07:00 david-b@pacbell.net # [PATCH] USB: usbtest, smp unlink modes # # Handle some SMP-visible unlink states better. # # drivers/usb/misc/usbtest.c # 2004/04/14 20:23:11-07:00 david-b@pacbell.net +3 -3 # USB: usbtest, smp unlink modes # # ChangeSet # 2004/04/23 14:50:19-07:00 greg@kroah.com # [PATCH] USB: fix devio compiler warnings created by previous patch. # # drivers/usb/core/devio.c # 2004/04/23 07:33:30-07:00 greg@kroah.com +2 -2 # USB: fix devio compiler warnings created by previous patch. # # ChangeSet # 2004/04/23 14:49:56-07:00 stern@rowland.harvard.edu # [PATCH] USB: Eliminate dead code from the UHCI driver # # I'm not sure what this piece of code is doing in the UHCI driver. It # looks like someone envisioned queuing several URBs for the same endpoint # simultaneously. Anyway, the driver can't do that and this code can never # run. # # drivers/usb/host/uhci-hcd.c # 2004/04/16 04:02:37-07:00 stern@rowland.harvard.edu +1 -11 # USB: Eliminate dead code from the UHCI driver # # ChangeSet # 2004/04/23 14:49:33-07:00 stern@rowland.harvard.edu # [PATCH] USB: Implement endpoint_disable() for UHCI # # This patch implements the endpoint_disable method for the UHCI driver, as # you requested a while back. It guarantees that during unbinding events # (disconnect, configuration change, rmmod) the UHCI driver will have # finished using every URB for the interface being unbound. It doesn't # quite guarantee that the completion handlers will have finished running, # but it would take a pretty unlikely race to violate that assumption. (I # think it's the same with the OHCI and EHCI drivers.) # # Despite the patch numbering this one applies _after_ as249, which is a # more important bugfix. # # drivers/usb/host/uhci-hcd.h # 2004/04/19 04:05:56-07:00 stern@rowland.harvard.edu +2 -0 # USB: Implement endpoint_disable() for UHCI # # drivers/usb/host/uhci-hcd.c # 2004/04/14 03:19:54-07:00 stern@rowland.harvard.edu +49 -0 # USB: Implement endpoint_disable() for UHCI # # ChangeSet # 2004/04/23 14:49:10-07:00 stern@rowland.harvard.edu # [PATCH] USB: unusual_devs.h update # # On Tue, 20 Apr 2004, Damian Ivereigh wrote: # # > Here is the output of dmesg when plugging in an IBM USB MemKey # > # > usb-storage: This device (0a16,8888,0100 S 06 P 50) has unneeded SubClass and Protocol entries in unusual_devs.h # > Please send a copy of this message to # # Thank you for sending this in. Greg and Pete, here's the patch. # # drivers/usb/storage/unusual_devs.h # 2004/04/19 05:11:29-07:00 stern@rowland.harvard.edu +1 -1 # USB: unusual_devs.h update # # ChangeSet # 2004/04/23 14:48:47-07:00 stern@rowland.harvard.edu # [PATCH] USB: Remove unusual_devs entries for Minolta DiMAGE 7, 7Hi # # It looks safe to conclude that the unusual_devs.h entries for the Minolta # DiMAGE 7x cameras aren't needed. (Michael has tested the 7Hi and it's # definitely unnecessary.) The two other DiMAGE entries probably aren't # needed either, but we don't have any evidence of that so I'm leaving them. # # drivers/usb/storage/unusual_devs.h # 2004/04/16 04:37:06-07:00 stern@rowland.harvard.edu +0 -16 # USB: Remove unusual_devs entries for Minolta DiMAGE 7, 7Hi # # ChangeSet # 2004/04/23 14:48:28-07:00 david-b@pacbell.net # [PATCH] USB: root hubs can report remote wakeup feature # # The patch lets HCDs report the root hub remote wakeup feature to usbcore # through config descriptors, and lets usbcore say whether or not remote # wakeup (of host from sleep, by devices) should be enabled. # # Both OHCI and UHCI HCDs have some remote wakeup support already; I'm not # too sure how well it works. Given (separate) patches, their root hubs # can start to act more like other hubs in this area too. That'll make # it easier to start using USB suspend mode. # # drivers/usb/core/hcd.h # 2004/04/13 11:48:39-07:00 david-b@pacbell.net +10 -1 # USB: root hubs can report remote wakeup feature # # drivers/usb/core/hcd.c # 2004/04/13 11:33:31-07:00 david-b@pacbell.net +28 -11 # USB: root hubs can report remote wakeup feature # # ChangeSet # 2004/04/23 14:48:02-07:00 david-b@pacbell.net # [PATCH] USB: fix usbfs iso interval problem # # In 2.6, ISO transfers on USB require a value for urb->interval ... which # usbfs didn't provide (until this patch), or let user mode drivers specify. # # This patch initializes the urb->interval from the endpoint's descriptor, # so ISO transfers should now work from userspace. It also fixes a related # problem for interrupt transfers. # # drivers/usb/core/devio.c # 2004/04/14 13:36:53-07:00 david-b@pacbell.net +7 -1 # USB: fix usbfs iso interval problem # # ChangeSet # 2004/04/23 12:58:38-07:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb # # CREDITS # 2004/04/23 12:58:35-07:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/04/19 19:45:10-07:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb # # include/linux/pci_ids.h # 2004/04/19 19:45:07-07:00 akpm@bix.(none) +0 -0 # Auto merged # # MAINTAINERS # 2004/04/19 19:45:07-07:00 akpm@bix.(none) +0 -0 # Auto merged # # CREDITS # 2004/04/19 19:45:06-07:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/04/07 20:17:13-07:00 akpm@bix.(none) # Merge bk://kernel.bkbits.net/gregkh/linux/usb-2.6 # into bix.(none):/usr/src/bk-usb # # drivers/usb/core/message.c # 2004/04/07 20:17:11-07:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/04/02 11:35:28-08:00 akpm@bix.(none) # Merge bk://kernel.bkbits.net/gregkh/linux/usb-2.6 # into bix.(none):/usr/src/bk-usb # # include/linux/pci_ids.h # 2004/04/02 11:35:25-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/04/01 15:16:14-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb # # CREDITS # 2004/04/01 15:16:11-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/03/31 19:24:39-08:00 akpm@bix.(none) # Merge bk://kernel.bkbits.net/gregkh/linux/usb-2.6 # into bix.(none):/usr/src/bk-usb # # include/linux/usb.h # 2004/03/31 19:24:37-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/usb/core/usb.c # 2004/03/31 19:24:37-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/usb/core/message.c # 2004/03/31 19:24:37-08:00 akpm@bix.(none) +0 -0 # Auto merged # # arch/ppc64/defconfig # 2004/03/31 19:24:36-08:00 akpm@bix.(none) +0 -0 # Auto merged # # arch/ppc64/configs/pSeries_defconfig # 2004/03/31 19:24:36-08:00 akpm@bix.(none) +0 -0 # Auto merged # # arch/ppc/defconfig # 2004/03/31 19:24:36-08:00 akpm@bix.(none) +0 -0 # Auto merged # # arch/ppc/configs/pmac_defconfig # 2004/03/31 19:24:36-08:00 akpm@bix.(none) +0 -0 # Auto merged # # arch/ppc/configs/common_defconfig # 2004/03/31 19:24:36-08:00 akpm@bix.(none) +0 -0 # Auto merged # # arch/parisc/configs/c3000_defconfig # 2004/03/31 19:24:36-08:00 akpm@bix.(none) +0 -0 # Auto merged # # arch/ia64/defconfig # 2004/03/31 19:24:36-08:00 akpm@bix.(none) +0 -0 # Auto merged # # arch/ia64/configs/zx1_defconfig # 2004/03/31 19:24:36-08:00 akpm@bix.(none) +0 -0 # Auto merged # # arch/ia64/configs/generic_defconfig # 2004/03/31 19:24:36-08:00 akpm@bix.(none) +0 -0 # Auto merged # # arch/arm/configs/neponset_defconfig # 2004/03/31 19:24:36-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/03/30 20:18:36-08:00 akpm@bix.(none) # Merge bk://kernel.bkbits.net/gregkh/linux/usb-2.6 # into bix.(none):/usr/src/bk-usb # # arch/ppc64/defconfig # 2004/03/30 20:18:33-08:00 akpm@bix.(none) +0 -0 # Auto merged # # arch/ppc64/configs/pSeries_defconfig # 2004/03/30 20:18:33-08:00 akpm@bix.(none) +0 -0 # Auto merged # # arch/ppc/defconfig # 2004/03/30 20:18:33-08:00 akpm@bix.(none) +0 -0 # Auto merged # # arch/ppc/configs/pmac_defconfig # 2004/03/30 20:18:33-08:00 akpm@bix.(none) +0 -0 # Auto merged # # arch/ppc/configs/common_defconfig # 2004/03/30 20:18:33-08:00 akpm@bix.(none) +0 -0 # Auto merged # # arch/parisc/configs/c3000_defconfig # 2004/03/30 20:18:33-08:00 akpm@bix.(none) +0 -0 # Auto merged # # arch/ia64/defconfig # 2004/03/30 20:18:33-08:00 akpm@bix.(none) +0 -0 # Auto merged # # arch/ia64/configs/zx1_defconfig # 2004/03/30 20:18:33-08:00 akpm@bix.(none) +0 -0 # Auto merged # # arch/ia64/configs/generic_defconfig # 2004/03/30 20:18:33-08:00 akpm@bix.(none) +0 -0 # Auto merged # # arch/arm/configs/neponset_defconfig # 2004/03/30 20:18:32-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/03/30 12:09:32-08:00 akpm@bix.(none) # Merge bk://kernel.bkbits.net/gregkh/linux/usb-2.6 # into bix.(none):/usr/src/bk-usb # # include/linux/usb.h # 2004/03/30 12:09:29-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/usb/core/usb.c # 2004/03/30 12:09:29-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/usb/core/message.c # 2004/03/30 12:09:29-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/03/29 18:05:43-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb # # MAINTAINERS # 2004/03/29 18:05:41-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/03/29 13:51:58-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb # # CREDITS # 2004/03/29 13:51:56-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/03/28 12:29:41-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb # # drivers/usb/core/message.c # 2004/03/28 12:29:38-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/03/27 02:28:18-08:00 akpm@bix.(none) # Merge bk://kernel.bkbits.net/gregkh/linux/usb-2.6 # into bix.(none):/usr/src/bk-usb # # drivers/usb/input/wacom.c # 2004/03/27 02:28:16-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/03/26 12:24:49-08:00 akpm@bix.(none) # Merge bk://kernel.bkbits.net/gregkh/linux/usb-2.6 # into bix.(none):/usr/src/bk-usb # # include/linux/usb_gadget.h # 2004/03/26 12:24:46-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/usb/core/usb.c # 2004/03/26 12:24:46-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/03/20 13:26:55-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb # # CREDITS # 2004/03/20 13:26:53-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/03/16 21:53:42-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb # # drivers/usb/input/wacom.c # 2004/03/16 21:53:39-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/usb/input/hid-core.c # 2004/03/16 21:53:39-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/03/16 12:59:58-08:00 akpm@bix.(none) # Merge bk://kernel.bkbits.net/gregkh/linux/usb-2.6 # into bix.(none):/usr/src/bk-usb # # include/linux/usb_gadget.h # 2004/03/16 12:59:47-08:00 akpm@bix.(none) +0 -0 # Auto merged # # include/linux/usb.h # 2004/03/16 12:59:47-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/usb/core/usb.c # 2004/03/16 12:59:46-08:00 akpm@bix.(none) +0 -0 # Auto merged # # MAINTAINERS # 2004/03/16 12:59:46-08:00 akpm@bix.(none) +0 -0 # Auto merged # # CREDITS # 2004/03/16 12:59:46-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/03/16 12:58:57-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb # # drivers/usb/input/wacom.c # 2004/03/16 12:58:47-08:00 akpm@bix.(none) +0 -4 # Auto merged # # drivers/usb/input/hid-core.c # 2004/03/16 12:58:47-08:00 akpm@bix.(none) +0 -0 # Auto merged # # CREDITS # 2004/03/16 12:58:46-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/03/14 11:03:00-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb # # include/linux/usb_gadget.h # 2004/03/14 11:02:47-08:00 akpm@bix.(none) +0 -0 # Auto merged # # include/linux/usb.h # 2004/03/14 11:02:47-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/usb/core/usb.c # 2004/03/14 11:02:47-08:00 akpm@bix.(none) +0 -0 # Auto merged # # MAINTAINERS # 2004/03/14 11:02:47-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/03/12 10:57:17-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb # # MAINTAINERS # 2004/03/12 10:57:02-08:00 akpm@bix.(none) +0 -0 # Auto merged # # CREDITS # 2004/03/12 10:57:01-08:00 akpm@bix.(none) +0 -0 # Auto merged # diff -Nru a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c --- a/drivers/usb/core/devio.c Sun Apr 25 23:06:52 2004 +++ b/drivers/usb/core/devio.c Sun Apr 25 23:06:52 2004 @@ -60,6 +60,11 @@ struct urb *urb; }; +static inline int connected (struct usb_device *dev) +{ + return dev->state != USB_STATE_NOTATTACHED; +} + static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig) { loff_t ret; @@ -87,14 +92,15 @@ static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) { struct dev_state *ps = (struct dev_state *)file->private_data; + struct usb_device *dev = ps->dev; ssize_t ret = 0; unsigned len; loff_t pos; int i; pos = *ppos; - down_read(&ps->devsem); - if (!ps->dev) { + down(&dev->serialize); + if (!connected(dev)) { ret = -ENODEV; goto err; } else if (pos < 0) { @@ -106,7 +112,7 @@ len = sizeof(struct usb_device_descriptor) - pos; if (len > nbytes) len = nbytes; - if (copy_to_user(buf, ((char *)&ps->dev->descriptor) + pos, len)) { + if (copy_to_user(buf, ((char *)&dev->descriptor) + pos, len)) { ret = -EFAULT; goto err; } @@ -118,9 +124,9 @@ } pos = sizeof(struct usb_device_descriptor); - for (i = 0; nbytes && i < ps->dev->descriptor.bNumConfigurations; i++) { + for (i = 0; nbytes && i < dev->descriptor.bNumConfigurations; i++) { struct usb_config_descriptor *config = - (struct usb_config_descriptor *)ps->dev->rawdescriptors[i]; + (struct usb_config_descriptor *)dev->rawdescriptors[i]; unsigned int length = le16_to_cpu(config->wTotalLength); if (*ppos < pos + length) { @@ -128,7 +134,7 @@ /* The descriptor may claim to be longer than it * really is. Here is the actual allocated length. */ unsigned alloclen = - ps->dev->config[i].desc.wTotalLength; + dev->config[i].desc.wTotalLength; len = length - (*ppos - pos); if (len > nbytes) @@ -138,7 +144,7 @@ if (alloclen > (*ppos - pos)) { alloclen -= (*ppos - pos); if (copy_to_user(buf, - ps->dev->rawdescriptors[i] + (*ppos - pos), + dev->rawdescriptors[i] + (*ppos - pos), min(len, alloclen))) { ret = -EFAULT; goto err; @@ -155,7 +161,7 @@ } err: - up_read(&ps->devsem); + up(&dev->serialize); return ret; } @@ -335,6 +341,7 @@ static void driver_disconnect(struct usb_interface *intf) { struct dev_state *ps = usb_get_intfdata (intf); + unsigned int ifnum = intf->altsetting->desc.bInterfaceNumber; if (!ps) return; @@ -343,13 +350,12 @@ * all pending I/O requests; 2.6 does that. */ - /* prevent new I/O requests */ - ps->dev = 0; - clear_bit(intf->cur_altsetting->desc.bInterfaceNumber, &ps->ifclaimed); + if (ifnum < 8*sizeof(ps->ifclaimed)) + clear_bit(ifnum, &ps->ifclaimed); usb_set_intfdata (intf, NULL); /* force async requests to complete */ - destroy_all_async (ps); + destroy_async_on_interface(ps, ifnum); } struct usb_driver usbdevfs_driver = { @@ -365,7 +371,7 @@ struct usb_interface *iface; int err; - if (intf >= 8*sizeof(ps->ifclaimed) || !dev + if (intf >= 8*sizeof(ps->ifclaimed) || intf >= dev->actconfig->desc.bNumInterfaces) return -EINVAL; /* already claimed */ @@ -395,7 +401,6 @@ return -EINVAL; err = -EINVAL; dev = ps->dev; - down(&dev->serialize); /* lock against other changes to driver bindings */ down_write(&usb_bus_type.subsys.rwsem); if (test_and_clear_bit(intf, &ps->ifclaimed)) { @@ -404,7 +409,6 @@ err = 0; } up_write(&usb_bus_type.subsys.rwsem); - up(&dev->serialize); return err; } @@ -506,7 +510,7 @@ lock_kernel(); ret = -ENOENT; - dev = inode->u.generic_ip; + dev = usb_get_dev(inode->u.generic_ip); if (!dev) { kfree(ps); goto out; @@ -518,7 +522,6 @@ INIT_LIST_HEAD(&ps->async_pending); INIT_LIST_HEAD(&ps->async_completed); init_waitqueue_head(&ps->wait); - init_rwsem(&ps->devsem); ps->discsignr = 0; ps->disctask = current; ps->disccontext = NULL; @@ -535,18 +538,21 @@ static int usbdev_release(struct inode *inode, struct file *file) { struct dev_state *ps = (struct dev_state *)file->private_data; + struct usb_device *dev = ps->dev; unsigned int i; - lock_kernel(); + down(&dev->serialize); list_del_init(&ps->list); - if (ps->dev) { + if (connected(dev)) { for (i = 0; ps->ifclaimed && i < 8*sizeof(ps->ifclaimed); i++) if (test_bit(i, &ps->ifclaimed)) releaseintf(ps, i); + destroy_all_async(ps); } - unlock_kernel(); - destroy_all_async(ps); + up(&dev->serialize); + usb_put_dev(dev); + ps->dev = NULL; kfree(ps); return 0; } @@ -702,13 +708,15 @@ return -EFAULT; if ((ret = findintfif(ps->dev, gd.interface)) < 0) return ret; + down_read(&usb_bus_type.subsys.rwsem); interface = ps->dev->actconfig->interface[ret]; - if (!interface->dev.driver) + if (!interface || !interface->dev.driver) { + up_read(&usb_bus_type.subsys.rwsem); return -ENODATA; + } strncpy(gd.driver, interface->dev.driver->name, sizeof(gd.driver)); - if (copy_to_user(arg, &gd, sizeof(gd))) - return -EFAULT; - return 0; + up_read(&usb_bus_type.subsys.rwsem); + return copy_to_user(arg, &gd, sizeof(gd)) ? -EFAULT : 0; } static int proc_connectinfo(struct dev_state *ps, void __user *arg) @@ -724,9 +732,6 @@ static int proc_resetdevice(struct dev_state *ps) { - /* FIXME when usb_reset_device() is fixed we'll need to grab - * ps->dev->serialize before calling it. - */ return usb_reset_device(ps->dev); } @@ -742,10 +747,8 @@ if ((ret = findintfif(ps->dev, setintf.interface)) < 0) return ret; interface = ps->dev->actconfig->interface[ret]; - if (interface->dev.driver) { - if ((ret = checkintf(ps, ret))) - return ret; - } + if ((ret = checkintf(ps, ret))) + return ret; if (usb_set_interface(ps->dev, setintf.interface, setintf.altsetting)) return -EINVAL; return 0; @@ -760,7 +763,6 @@ if (get_user(u, (unsigned int __user *)arg)) return -EFAULT; - down(&ps->dev->serialize); actconfig = ps->dev->actconfig; /* Don't touch the device if any interfaces are claimed. @@ -796,7 +798,6 @@ else status = usb_set_configuration(ps->dev, u); } - up(&ps->dev->serialize); return status; } @@ -873,6 +874,9 @@ /* arbitrary limit */ if (uurb.number_of_packets < 1 || uurb.number_of_packets > 128) return -EINVAL; + if (!(ep_desc = usb_epnum_to_ep_desc(ps->dev, uurb.endpoint))) + return -ENOENT; + interval = 1 << min (15, ep_desc->bInterval - 1); isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * uurb.number_of_packets; if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL))) return -ENOMEM; @@ -898,7 +902,10 @@ uurb.number_of_packets = 0; if (!(ep_desc = usb_epnum_to_ep_desc(ps->dev, uurb.endpoint))) return -ENOENT; - interval = ep_desc->bInterval; + if (ps->dev->speed == USB_SPEED_HIGH) + interval = 1 << min (15, ep_desc->bInterval - 1); + else + interval = ep_desc->bInterval; if (uurb.buffer_length > 16384) return -EINVAL; if (!access_ok((uurb.endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb.buffer, uurb.buffer_length)) @@ -1012,18 +1019,19 @@ DECLARE_WAITQUEUE(wait, current); struct async *as = NULL; void __user *addr; + struct usb_device *dev = ps->dev; int ret; add_wait_queue(&ps->wait, &wait); - while (ps->dev) { + while (connected(dev)) { __set_current_state(TASK_INTERRUPTIBLE); if ((as = async_getcompleted(ps))) break; if (signal_pending(current)) break; - up_read(&ps->devsem); + up(&dev->serialize); schedule(); - down_read(&ps->devsem); + down(&dev->serialize); } remove_wait_queue(&ps->wait, &wait); set_current_state(TASK_RUNNING); @@ -1125,13 +1133,12 @@ } } - if (!ps->dev) { + if (!connected(ps->dev)) { if (buf) kfree(buf); return -ENODEV; } - down(&ps->dev->serialize); if (ps->dev->state != USB_STATE_CONFIGURED) retval = -ENODEV; else if (!(ifp = usb_ifnum_to_if (ps->dev, ctrl.ifno))) @@ -1169,7 +1176,6 @@ } up_read(&usb_bus_type.subsys.rwsem); } - up(&ps->dev->serialize); /* cleanup and return */ if (retval >= 0 @@ -1190,13 +1196,14 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct dev_state *ps = (struct dev_state *)file->private_data; + struct usb_device *dev = ps->dev; int ret = -ENOTTY; if (!(file->f_mode & FMODE_WRITE)) return -EPERM; - down_read(&ps->devsem); - if (!ps->dev) { - up_read(&ps->devsem); + down(&dev->serialize); + if (!connected(dev)) { + up(&dev->serialize); return -ENODEV; } switch (cmd) { @@ -1278,7 +1285,7 @@ ret = proc_ioctl(ps, (void __user *) arg); break; } - up_read(&ps->devsem); + up(&dev->serialize); if (ret >= 0) inode->i_atime = CURRENT_TIME; return ret; @@ -1293,7 +1300,7 @@ poll_wait(file, &ps->wait, wait); if (file->f_mode & FMODE_WRITE && !list_empty(&ps->async_completed)) mask |= POLLOUT | POLLWRNORM; - if (!ps->dev) + if (!connected(ps->dev)) mask |= POLLERR | POLLHUP; return mask; } diff -Nru a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c --- a/drivers/usb/core/hcd.c Sun Apr 25 23:06:52 2004 +++ b/drivers/usb/core/hcd.c Sun Apr 25 23:06:52 2004 @@ -171,10 +171,10 @@ 0x01, /* __u8 bNumInterfaces; (1) */ 0x01, /* __u8 bConfigurationValue; */ 0x00, /* __u8 iConfiguration; */ - 0x40, /* __u8 bmAttributes; - Bit 7: Bus-powered, + 0xc0, /* __u8 bmAttributes; + Bit 7: must be set, 6: Self-powered, - 5 Remote-wakwup, + 5: Remote wakeup, 4..0: resvd */ 0x00, /* __u8 MaxPower; */ @@ -218,10 +218,10 @@ 0x01, /* __u8 bNumInterfaces; (1) */ 0x01, /* __u8 bConfigurationValue; */ 0x00, /* __u8 iConfiguration; */ - 0x40, /* __u8 bmAttributes; - Bit 7: Bus-powered, + 0xc0, /* __u8 bmAttributes; + Bit 7: must be set, 6: Self-powered, - 5 Remote-wakwup, + 5: Remote wakeup, 4..0: resvd */ 0x00, /* __u8 MaxPower; */ @@ -324,13 +324,15 @@ /* Root hub control transfers execute synchronously */ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) { - struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *) urb->setup_packet; + struct usb_ctrlrequest *cmd; u16 typeReq, wValue, wIndex, wLength; const u8 *bufp = 0; u8 *ubuf = urb->transfer_buffer; int len = 0; + int patch_wakeup = 0; unsigned long flags; + cmd = (struct usb_ctrlrequest *) urb->setup_packet; typeReq = (cmd->bRequestType << 8) | cmd->bRequest; wValue = le16_to_cpu (cmd->wValue); wIndex = le16_to_cpu (cmd->wIndex); @@ -347,13 +349,21 @@ /* DEVICE REQUESTS */ case DeviceRequest | USB_REQ_GET_STATUS: - // DEVICE_REMOTE_WAKEUP - ubuf [0] = 1; // selfpowered + ubuf [0] = (hcd->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP) + | (1 << USB_DEVICE_SELF_POWERED); ubuf [1] = 0; - /* FALLTHROUGH */ + break; case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: + if (wValue == USB_DEVICE_REMOTE_WAKEUP) + hcd->remote_wakeup = 0; + else + goto error; + break; case DeviceOutRequest | USB_REQ_SET_FEATURE: - dev_dbg (hcd->self.controller, "no device features yet yet\n"); + if (hcd->can_wakeup && wValue == USB_DEVICE_REMOTE_WAKEUP) + hcd->remote_wakeup = 1; + else + goto error; break; case DeviceRequest | USB_REQ_GET_CONFIGURATION: ubuf [0] = 1; @@ -379,6 +389,8 @@ bufp = fs_rh_config_descriptor; len = sizeof fs_rh_config_descriptor; } + if (hcd->can_wakeup) + patch_wakeup = 1; break; case USB_DT_STRING << 8: urb->actual_length = rh_string ( @@ -444,6 +456,11 @@ urb->actual_length = len; // always USB_DIR_IN, toward host memcpy (ubuf, bufp, len); + + /* report whether RH hardware supports remote wakeup */ + if (patch_wakeup) + ((struct usb_config_descriptor *)ubuf)->bmAttributes + |= USB_CONFIG_ATT_WAKEUP; } /* any errors get returned through the urb completion */ @@ -762,10 +779,22 @@ set_bit (devnum, usb_dev->bus->devmap.devicemap); usb_dev->state = USB_STATE_ADDRESS; + usb_dev->epmaxpacketin[0] = usb_dev->epmaxpacketout[0] = 64; + retval = usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE); + if (retval != sizeof usb_dev->descriptor) { + dev_dbg (parent_dev, "can't read %s device descriptor %d\n", + usb_dev->dev.bus_id, retval); + return (retval < 0) ? retval : -EMSGSIZE; + } + + (void) usb_get_dev (usb_dev); + down (&usb_dev->serialize); retval = usb_new_device (usb_dev); if (retval) dev_err (parent_dev, "can't register root hub for %s, %d\n", usb_dev->dev.bus_id, retval); + up (&usb_dev->serialize); + usb_put_dev (usb_dev); return retval; } EXPORT_SYMBOL (usb_register_root_hub); diff -Nru a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h --- a/drivers/usb/core/hcd.h Sun Apr 25 23:06:52 2004 +++ b/drivers/usb/core/hcd.h Sun Apr 25 23:06:52 2004 @@ -74,6 +74,8 @@ */ struct hc_driver *driver; /* hw-specific hooks */ unsigned saw_irq : 1; + unsigned can_wakeup:1; /* hw supports wakeup? */ + unsigned remote_wakeup:1;/* sw should use wakeup? */ int irq; /* irq allocated */ void *regs; /* device memory/io */ @@ -344,9 +346,16 @@ extern int usb_register_root_hub (struct usb_device *usb_dev, struct device *parent_dev); -/* for portability to 2.4, hcds should call this */ static inline int hcd_register_root (struct usb_hcd *hcd) { + /* hcd->driver->start() reported can_wakeup, probably with + * assistance from board's boot firmware. + * NOTE: normal devices won't enable wakeup by default. + */ + if (hcd->can_wakeup) + dev_dbg (hcd->self.controller, "supports USB remote wakeup\n"); + hcd->remote_wakeup = hcd->can_wakeup; + return usb_register_root_hub ( hcd_to_bus (hcd)->root_hub, hcd->self.controller); } diff -Nru a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c --- a/drivers/usb/core/hub.c Sun Apr 25 23:06:52 2004 +++ b/drivers/usb/core/hub.c Sun Apr 25 23:06:52 2004 @@ -373,12 +373,13 @@ struct usb_device *dev; int i; - /* Enable power to the ports */ - dev_dbg(hubdev(interface_to_usbdev(hub->intf)), - "enabling power on all ports\n"); - dev = interface_to_usbdev(hub->intf); - for (i = 0; i < hub->descriptor->bNbrPorts; i++) - set_port_feature(dev, i + 1, USB_PORT_FEAT_POWER); + /* if hub supports power switching, enable power on each port */ + if ((hub->descriptor->wHubCharacteristics & HUB_CHAR_LPSM) < 2) { + dev_dbg(&hub->intf->dev, "enabling power on all ports\n"); + dev = interface_to_usbdev(hub->intf); + for (i = 0; i < hub->descriptor->bNbrPorts; i++) + set_port_feature(dev, i + 1, USB_PORT_FEAT_POWER); + } /* Wait for power to be enabled */ wait_ms(hub->descriptor->bPwrOn2PwrGood * 2); @@ -545,8 +546,25 @@ dev_dbg(hub_dev, "power on to power good time: %dms\n", hub->descriptor->bPwrOn2PwrGood * 2); - dev_dbg(hub_dev, "hub controller current requirement: %dmA\n", - hub->descriptor->bHubContrCurrent); + + /* power budgeting mostly matters with bus-powered hubs, + * and battery-powered root hubs (may provide just 8 mA). + */ + ret = usb_get_status(dev, USB_RECIP_DEVICE, 0, &hubstatus); + if (ret < 0) { + message = "can't get hubdev status"; + goto fail; + } + cpu_to_le16s(&hubstatus); + if ((hubstatus & (1 << USB_DEVICE_SELF_POWERED)) == 0) { + dev_dbg(hub_dev, "hub controller current requirement: %dmA\n", + hub->descriptor->bHubContrCurrent); + hub->power_budget = (501 - hub->descriptor->bHubContrCurrent) + / 2; + dev_dbg(hub_dev, "%dmA bus power budget for children\n", + hub->power_budget * 2); + } + ret = hub_hub_status(hub, &hubstatus, &hubchange); if (ret < 0) { @@ -554,12 +572,11 @@ goto fail; } - /* FIXME implement per-port power budgeting; - * enable it for bus-powered hubs. - */ - dev_dbg(hub_dev, "local power source is %s\n", - (hubstatus & HUB_STATUS_LOCAL_POWER) - ? "lost (inactive)" : "good"); + /* local power status reports aren't always correct */ + if (dev->actconfig->desc.bmAttributes & USB_CONFIG_ATT_SELFPOWER) + dev_dbg(hub_dev, "local power source is %s\n", + (hubstatus & HUB_STATUS_LOCAL_POWER) + ? "lost (inactive)" : "good"); if ((hub->descriptor->wHubCharacteristics & HUB_CHAR_OCPM) == 0) dev_dbg(hub_dev, "%sover-current condition exists\n", @@ -611,6 +628,8 @@ return ret; } +static unsigned highspeed_hubs; + static void hub_disconnect(struct usb_interface *intf) { struct usb_hub *hub = usb_get_intfdata (intf); @@ -620,6 +639,9 @@ if (!hub) return; + if (interface_to_usbdev(intf)->speed == USB_SPEED_HIGH) + highspeed_hubs--; + usb_set_intfdata (intf, NULL); spin_lock_irqsave(&hub_event_lock, flags); hub->urb_complete = &urb_complete; @@ -731,6 +753,9 @@ usb_set_intfdata (intf, hub); + if (dev->speed == USB_SPEED_HIGH) + highspeed_hubs++; + if (hub_configure(hub, endpoint) >= 0) return 0; @@ -841,8 +866,11 @@ return ret; } -#define HUB_RESET_TRIES 5 -#define HUB_PROBE_TRIES 2 +#define PORT_RESET_TRIES 5 +#define SET_ADDRESS_TRIES 2 +#define GET_DESCRIPTOR_TRIES 2 +#define SET_CONFIG_TRIES 2 + #define HUB_ROOT_RESET_TIME 50 /* times are in msec */ #define HUB_SHORT_RESET_TIME 10 #define HUB_LONG_RESET_TIME 200 @@ -907,7 +935,7 @@ int i, status; /* Reset the port */ - for (i = 0; i < HUB_RESET_TRIES; i++) { + for (i = 0; i < PORT_RESET_TRIES; i++) { set_port_feature(hub, port + 1, USB_PORT_FEAT_RESET); /* return on disconnect or reset */ @@ -1003,40 +1031,20 @@ return ((portstatus&USB_PORT_STAT_CONNECTION)) ? 0 : 1; } -static void hub_port_connect_change(struct usb_hub *hubstate, int port, - u16 portstatus, u16 portchange) +/* reset device, (re)assign address, get device descriptor. + * device connection is stable, no more debouncing needed. + * returns device in USB_STATE_ADDRESS, except on error. + * on error return, device is no longer usable (ref dropped). + * + * caller owns dev->serialize for the device, guarding against + * config changes and disconnect processing. + */ +static int +hub_port_init (struct usb_device *hub, struct usb_device *dev, int port) { - struct usb_device *hub = interface_to_usbdev(hubstate->intf); - struct usb_device *dev; - unsigned int delay = HUB_SHORT_RESET_TIME; - int i; - - dev_dbg (&hubstate->intf->dev, - "port %d, status %x, change %x, %s\n", - port + 1, portstatus, portchange, portspeed (portstatus)); - - /* Clear the connection change status */ - clear_port_feature(hub, port + 1, USB_PORT_FEAT_C_CONNECTION); - - /* Disconnect any existing devices under this port */ - if (hub->children[port]) - usb_disconnect(&hub->children[port]); - - /* Return now if nothing is connected */ - if (!(portstatus & USB_PORT_STAT_CONNECTION)) { - if (portstatus & USB_PORT_STAT_ENABLE) - hub_port_disable(hub, port); - - return; - } - - if (hub_port_debounce(hub, port)) { - dev_err (&hubstate->intf->dev, - "connect-debounce failed, port %d disabled\n", - port+1); - hub_port_disable(hub, port); - return; - } + int i, j, retval = -ENODEV; + unsigned delay = HUB_SHORT_RESET_TIME; + enum usb_device_speed oldspeed = dev->speed; /* root hub ports have a slightly longer reset period * (from USB 2.0 spec, section 7.1.7.5) @@ -1046,31 +1054,53 @@ /* Some low speed devices have problems with the quick delay, so */ /* be a bit pessimistic with those devices. RHbug #23670 */ - if (portstatus & USB_PORT_STAT_LOW_SPEED) + if (oldspeed == USB_SPEED_LOW) delay = HUB_LONG_RESET_TIME; down(&usb_address0_sem); - for (i = 0; i < HUB_PROBE_TRIES; i++) { - - /* Allocate a new device struct */ - dev = usb_alloc_dev(hub, hub->bus, port); - if (!dev) { - dev_err (&hubstate->intf->dev, - "couldn't allocate usb_device\n"); - break; - } - - dev->state = USB_STATE_POWERED; - - /* Reset the device, and detect its speed */ - if (hub_port_reset(hub, port, dev, delay)) { - usb_put_dev(dev); - break; - } - - /* Find a new address for it */ + /* Reset the device; full speed may morph to high speed */ + switch (hub_port_reset(hub, port, dev, delay)) { + case 0: /* success, speed is known */ + break; + case 1: /* disconnect, give to companion */ + retval = -EBUSY; + /* FALL THROUGH */ + default: /* error */ + goto fail; + } + if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != dev->speed) { + dev_dbg(&dev->dev, "device reset changed speed!\n"); + goto fail; + } + + /* USB 2.0 section 5.5.3 talks about ep0 maxpacket ... + * it's fixed size except for full speed devices. + */ + switch (dev->speed) { + case USB_SPEED_HIGH: /* fixed at 64 */ + i = 64; + break; + case USB_SPEED_FULL: /* 8, 16, 32, or 64 */ + /* to determine the ep0 maxpacket size, read the first 8 + * bytes from the device descriptor to get bMaxPacketSize0; + * then correct our initial (small) guess. + */ + // FALLTHROUGH + case USB_SPEED_LOW: /* fixed at 8 */ + i = 8; + break; + default: + goto fail; + } + dev->epmaxpacketin [0] = i; + dev->epmaxpacketout[0] = i; + + /* set the address */ + if (dev->devnum <= 0) { usb_choose_address(dev); + if (dev->devnum <= 0) + goto fail; /* Set up TT records, if needed */ if (hub->tt) { @@ -1078,12 +1108,21 @@ dev->ttport = hub->ttport; } else if (dev->speed != USB_SPEED_HIGH && hub->speed == USB_SPEED_HIGH) { + struct usb_hub *hubstate; + + hubstate = usb_get_intfdata (hub->actconfig + ->interface[0]); dev->tt = &hubstate->tt; dev->ttport = port + 1; } - dev_info (&dev->dev, - "new %s speed USB device using address %d\n", + /* force the right log message (below) at low speed */ + oldspeed = USB_SPEED_UNKNOWN; + } + + dev_info (&dev->dev, + "%s %s speed USB device using address %d\n", + (oldspeed == USB_SPEED_UNKNOWN) ? "new" : "reset", ({ char *speed; switch (dev->speed) { case USB_SPEED_LOW: speed = "low"; break; case USB_SPEED_FULL: speed = "full"; break; @@ -1091,23 +1130,258 @@ default: speed = "?"; break; }; speed;}), dev->devnum); + + /* Why interleave GET_DESCRIPTOR and SET_ADDRESS this way? + * Because device hardware and firmware is sometimes buggy in + * this area, and this is how Linux has done it for ages. + * Change it cautiously. + * + * NOTE: Windows gets the descriptor first, seemingly to help + * work around device bugs like "can't use addresses with bit 3 + * set in certain configurations". Yes, really. + */ + for (i = 0; i < GET_DESCRIPTOR_TRIES; ++i) { + for (j = 0; j < SET_ADDRESS_TRIES; ++j) { + retval = usb_set_address(dev); + if (retval >= 0) + break; + wait_ms(200); + } + if (retval < 0) { + dev_err(&dev->dev, + "device not accepting address %d, error %d\n", + dev->devnum, retval); + fail: + hub_port_disable(hub, port); + clear_bit(dev->devnum, dev->bus->devmap.devicemap); + dev->devnum = -1; + usb_put_dev(dev); + up(&usb_address0_sem); + return retval; + } + + /* cope with hardware quirkiness: + * - let SET_ADDRESS settle, some device hardware wants it + * - read ep0 maxpacket even for high and low speed, + */ + wait_ms(10); + retval = usb_get_device_descriptor(dev, 8); + if (retval >= 8) + break; + wait_ms(100); + } + if (retval != 8) { + dev_err(&dev->dev, "device descriptor read/%s, error %d\n", + "8", retval); + if (retval >= 0) + retval = -EMSGSIZE; + goto fail; + } + if (dev->speed == USB_SPEED_FULL + && (dev->epmaxpacketin [0] + != dev->descriptor.bMaxPacketSize0)) { + usb_disable_endpoint(dev, 0); + usb_endpoint_running(dev, 0, 1); + usb_endpoint_running(dev, 0, 0); + dev->epmaxpacketin [0] = dev->descriptor.bMaxPacketSize0; + dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0; + } + + retval = usb_get_device_descriptor(dev, USB_DT_DEVICE_SIZE); + if (retval < (signed)sizeof(dev->descriptor)) { + dev_err(&dev->dev, "device descriptor read/%s, error %d\n", + "all", retval); + if (retval >= 0) + retval = -ENOMSG; + goto fail; + } - /* Run it through the hoops (find a driver, etc) */ - if (usb_new_device(dev) == 0) { - hub->children[port] = dev; - goto done; + /* now dev is visible to other tasks */ + hub->children[port] = dev; + + up(&usb_address0_sem); + return 0; +} + +static void +check_highspeed (struct usb_hub *hub, struct usb_device *dev, int port) +{ + struct usb_qualifier_descriptor *qual; + int status; + + qual = kmalloc (sizeof *qual, SLAB_KERNEL); + if (qual == 0) + return; + + status = usb_get_descriptor (dev, USB_DT_DEVICE_QUALIFIER, 0, + qual, sizeof *qual); + if (status == sizeof *qual) { + dev_info(&dev->dev, "not running at top speed; " + "connect to a high speed hub\n"); + /* hub LEDs are probably harder to miss than syslog */ + if (hub->has_indicators) { + hub->indicator[port] = INDICATOR_GREEN_BLINK; + schedule_work (&hub->leds); } + } + kfree (qual); +} - /* Free the configuration if there was an error */ - usb_put_dev(dev); +static unsigned +hub_power_remaining (struct usb_hub *hubstate, struct usb_device *hub) +{ + int remaining; + unsigned i; - /* Switch to a long reset time */ - delay = HUB_LONG_RESET_TIME; + remaining = hubstate->power_budget; + if (!remaining) /* self-powered */ + return 0; + + for (i = 0; i < hub->maxchild; i++) { + struct usb_device *dev = hub->children[i]; + int delta; + + if (!dev) + continue; + + if (dev->actconfig) + delta = dev->actconfig->desc.bMaxPower; + else + delta = 50; + // dev_dbg(&dev->dev, "budgeted %dmA\n", 2 * delta); + remaining -= delta; + } + if (remaining < 0) { + dev_warn(&hubstate->intf->dev, + "%dmA over power budget!\n", + -2 * remaining); + remaining = 0; } + return remaining; +} + +static void hub_port_connect_change(struct usb_hub *hubstate, int port, + u16 portstatus, u16 portchange) +{ + struct usb_device *hub = interface_to_usbdev(hubstate->intf); + int status, i; + + dev_dbg (&hubstate->intf->dev, + "port %d, status %04x, change %04x, %s\n", + port + 1, portstatus, portchange, portspeed (portstatus)); + + /* Clear the connection change status */ + clear_port_feature(hub, port + 1, USB_PORT_FEAT_C_CONNECTION); - hub_port_disable(hub, port); + if (hubstate->has_indicators) { + set_port_led(hub, hubstate, port + 1, HUB_LED_AUTO); + hubstate->indicator[port] = INDICATOR_AUTO; + } + + /* Disconnect any existing devices under this port */ + if (hub->children[port]) + usb_disconnect(&hub->children[port]); + + /* Return now if nothing is connected */ + if (!(portstatus & USB_PORT_STAT_CONNECTION)) { + if (portstatus & USB_PORT_STAT_ENABLE) + goto done; + return; + } + + if (hub_port_debounce(hub, port)) { + dev_err (&hubstate->intf->dev, + "connect-debounce failed, port %d disabled\n", + port+1); + goto done; + } + + for (i = 0; i < SET_CONFIG_TRIES; i++) { + struct usb_device *dev; + + /* reallocate for each attempt, since references + * to the previous one can escape in various ways + */ + dev = usb_alloc_dev(hub, hub->bus, port); + if (!dev) { + dev_err (&hubstate->intf->dev, + "couldn't allocate port %d usb_device\n", port+1); + goto done; + } + dev->state = USB_STATE_POWERED; + + /* hub can tell if it's lowspeed already: D- pullup (not D+) */ + if (portstatus & USB_PORT_STAT_LOW_SPEED) + dev->speed = USB_SPEED_LOW; + else + dev->speed = USB_SPEED_UNKNOWN; + + /* reset, set address, get descriptor, add to hub's children */ + down (&dev->serialize); + status = hub_port_init(hub, dev, port); + if (status == -EBUSY) + break; + if (status < 0) + continue; + + /* consecutive bus-powered hubs aren't reliable; they can + * violate the voltage drop budget. if the new child has + * a "powered" LED, users should notice we didn't enable it + * (without reading syslog), even without per-port LEDs + * on the parent. + */ + if (dev->descriptor.bDeviceClass == USB_CLASS_HUB + && hubstate->power_budget) { + u16 devstat; + + status = usb_get_status(dev, USB_RECIP_DEVICE, 0, + &devstat); + if (status < 0) { + dev_dbg(&dev->dev, "get status %d ?\n", status); + continue; + } + cpu_to_le16s(&hubstatus); + if ((devstat & (1 << USB_DEVICE_SELF_POWERED)) == 0) { + dev_err(&dev->dev, + "can't connect bus-powered hub " + "to this port\n"); + if (hubstate->has_indicators) { + hubstate->indicator[port] = + INDICATOR_AMBER_BLINK; + schedule_work (&hubstate->leds); + } + hub->children[port] = NULL; + usb_put_dev(dev); + hub_port_disable(hub, port); + return; + } + } + + /* check for devices running slower than they could */ + if (dev->descriptor.bcdUSB >= 0x0200 + && dev->speed == USB_SPEED_FULL + && highspeed_hubs != 0) + check_highspeed (hubstate, dev, port); + + /* Run it through the hoops (find a driver, etc) */ + status = usb_new_device(dev); + if (status != 0) { + hub->children[port] = NULL; + continue; + } + up (&dev->serialize); + + status = hub_power_remaining(hubstate, hub); + if (status) + dev_dbg(&hubstate->intf->dev, + "%dmA power budget left\n", + 2 * status); + + return; + } + done: - up(&usb_address0_sem); + hub_port_disable(hub, port); } static void hub_events(void) @@ -1285,9 +1559,6 @@ .id_table = hub_id_table, }; -/* - * This should be a separate module. - */ int usb_hub_init(void) { pid_t pid; diff -Nru a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h --- a/drivers/usb/core/hub.h Sun Apr 25 23:06:52 2004 +++ b/drivers/usb/core/hub.h Sun Apr 25 23:06:52 2004 @@ -209,6 +209,8 @@ struct semaphore khubd_sem; struct usb_tt tt; /* Transaction Translator */ + u8 power_budget; /* in 2mA units; or zero */ + unsigned has_indicators:1; enum hub_led_mode indicator[USB_MAXCHILDREN]; struct work_struct leds; diff -Nru a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c --- a/drivers/usb/core/inode.c Sun Apr 25 23:06:52 2004 +++ b/drivers/usb/core/inode.c Sun Apr 25 23:06:52 2004 @@ -717,9 +717,6 @@ while (!list_empty(&dev->filelist)) { ds = list_entry(dev->filelist.next, struct dev_state, list); list_del_init(&ds->list); - down_write(&ds->devsem); - ds->dev = NULL; - up_write(&ds->devsem); if (ds->discsignr) { sinfo.si_signo = SIGPIPE; sinfo.si_errno = EPIPE; diff -Nru a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c --- a/drivers/usb/core/usb.c Sun Apr 25 23:06:52 2004 +++ b/drivers/usb/core/usb.c Sun Apr 25 23:06:52 2004 @@ -1064,92 +1064,29 @@ } /* - * By the time we get here, we chose a new device address - * and is in the default state. We need to identify the thing and - * get the ball rolling.. + * usb_new_device - perform initial device setup (usbcore-internal) + * @dev: newly addressed device (in ADDRESS state) * - * Returns 0 for success, != 0 for error. + * This is called with devices which have been enumerated, but not yet + * configured. The device descriptor is available, but not descriptors + * for any device configuration. The caller owns dev->serialize, and + * the device is not visible through sysfs or other filesystem code. + * + * Returns 0 for success (device is configured and listed, with its + * interfaces, in sysfs); else a negative errno value. On error, one + * reference count to the device has been dropped. * * This call is synchronous, and may not be used in an interrupt context. * * Only the hub driver should ever call this; root hub registration * uses it only indirectly. */ -#define NEW_DEVICE_RETRYS 2 -#define SET_ADDRESS_RETRYS 2 int usb_new_device(struct usb_device *dev) { - int err = -EINVAL; + int err; int i; - int j; int config; - /* USB 2.0 section 5.5.3 talks about ep0 maxpacket ... - * it's fixed size except for full speed devices. - */ - switch (dev->speed) { - case USB_SPEED_HIGH: /* fixed at 64 */ - i = 64; - break; - case USB_SPEED_FULL: /* 8, 16, 32, or 64 */ - /* to determine the ep0 maxpacket size, read the first 8 - * bytes from the device descriptor to get bMaxPacketSize0; - * then correct our initial (small) guess. - */ - // FALLTHROUGH - case USB_SPEED_LOW: /* fixed at 8 */ - i = 8; - break; - default: - goto fail; - } - dev->epmaxpacketin [0] = i; - dev->epmaxpacketout[0] = i; - - for (i = 0; i < NEW_DEVICE_RETRYS; ++i) { - - for (j = 0; j < SET_ADDRESS_RETRYS; ++j) { - err = usb_set_address(dev); - if (err >= 0) - break; - wait_ms(200); - } - if (err < 0) { - dev_err(&dev->dev, - "device not accepting address %d, error %d\n", - dev->devnum, err); - goto fail; - } - - wait_ms(10); /* Let the SET_ADDRESS settle */ - - /* high and low speed devices don't need this... */ - err = usb_get_device_descriptor(dev, 8); - if (err >= 8) - break; - wait_ms(100); - } - - if (err < 8) { - dev_err(&dev->dev, "device descriptor read/8, error %d\n", err); - goto fail; - } - if (dev->speed == USB_SPEED_FULL) { - usb_disable_endpoint(dev, 0); - usb_endpoint_running(dev, 0, 1); - usb_endpoint_running(dev, 0, 0); - dev->epmaxpacketin [0] = dev->descriptor.bMaxPacketSize0; - dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0; - } - - /* USB device state == addressed ... still not usable */ - - err = usb_get_device_descriptor(dev, sizeof(dev->descriptor)); - if (err != (signed)sizeof(dev->descriptor)) { - dev_err(&dev->dev, "device descriptor read/all, error %d\n", err); - goto fail; - } - err = usb_get_configuration(dev); if (err < 0) { dev_err(&dev->dev, "can't read configurations, error %d\n", @@ -1170,13 +1107,10 @@ usb_show_string(dev, "SerialNumber", dev->descriptor.iSerialNumber); #endif - down(&dev->serialize); - /* put device-specific files into sysfs */ err = device_add (&dev->dev); if (err) { dev_err(&dev->dev, "can't device_add, error %d\n", err); - up(&dev->serialize); goto fail; } usb_create_driverfs_dev_files (dev); @@ -1211,7 +1145,6 @@ dev->descriptor.bNumConfigurations); } err = usb_set_configuration(dev, config); - up(&dev->serialize); if (err) { dev_err(&dev->dev, "can't set config #%d, error %d\n", config, err); @@ -1226,9 +1159,10 @@ return 0; fail: - dev->state = USB_STATE_DEFAULT; + dev->state = USB_STATE_NOTATTACHED; clear_bit(dev->devnum, dev->bus->devmap.devicemap); dev->devnum = -1; + usb_put_dev(dev); return err; } diff -Nru a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c --- a/drivers/usb/host/uhci-hcd.c Sun Apr 25 23:06:52 2004 +++ b/drivers/usb/host/uhci-hcd.c Sun Apr 25 23:06:52 2004 @@ -157,8 +157,8 @@ return td; } -static inline void uhci_fill_td(struct uhci_td *td, __u32 status, - __u32 token, __u32 buffer) +static inline void uhci_fill_td(struct uhci_td *td, u32 status, + u32 token, u32 buffer) { td->status = cpu_to_le32(status); td->token = cpu_to_le32(token); @@ -184,11 +184,11 @@ list_add_tail(&td->fl_list, &ftd->fl_list); td->link = ltd->link; - mb(); + wmb(); ltd->link = cpu_to_le32(td->dma_handle); } else { td->link = uhci->fl->frame[framenum]; - mb(); + wmb(); uhci->fl->frame[framenum] = cpu_to_le32(td->dma_handle); uhci->fl->frame_cpu[framenum] = td; } @@ -218,7 +218,7 @@ ptd->link = td->link; } - mb(); + wmb(); td->link = UHCI_PTR_TERM; list_del_init(&td->fl_list); @@ -332,17 +332,7 @@ /* Grab the last QH */ lqh = list_entry(skelqh->list.prev, struct uhci_qh, list); - /* - * Patch this endpoint's URB's QHs to point to the next skelqh: - * skelqh --> ... lqh --> newqh --> next skelqh - * Do this first, so the HC always sees the right QH after this one. - */ - list_for_each (tmp, &urbp->queue_list) { - struct urb_priv *turbp = - list_entry(tmp, struct urb_priv, queue_list); - - turbp->qh->link = lqh->link; - } + /* Point to the next skelqh */ urbp->qh->link = lqh->link; wmb(); /* Ordering is important */ @@ -362,15 +352,15 @@ * * The HC could see (and use!) any of these as we write them. */ + lqh->link = cpu_to_le32(urbp->qh->dma_handle) | UHCI_PTR_QH; if (lqh->urbp) { list_for_each (tmp, &lqh->urbp->queue_list) { struct urb_priv *turbp = list_entry(tmp, struct urb_priv, queue_list); - turbp->qh->link = cpu_to_le32(urbp->qh->dma_handle) | UHCI_PTR_QH; + turbp->qh->link = lqh->link; } } - lqh->link = cpu_to_le32(urbp->qh->dma_handle) | UHCI_PTR_QH; list_add_tail(&urbp->qh->list, &skelqh->list); } @@ -382,7 +372,7 @@ static void uhci_remove_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) { struct uhci_qh *pqh; - __u32 newlink; + u32 newlink; if (!qh) return; @@ -423,7 +413,7 @@ turbp->qh->link = newlink; } } - mb(); + wmb(); /* Leave qh->link in case the HC is on the QH now, it will */ /* continue the rest of the schedule */ @@ -510,7 +500,7 @@ /* All qh's in the queue need to link to the next queue */ urbp->qh->link = eurbp->qh->link; - mb(); /* Make sure we flush everything */ + wmb(); /* Make sure we flush everything */ lltd->link = cpu_to_le32(urbp->qh->dma_handle) | UHCI_PTR_QH; @@ -1044,9 +1034,13 @@ usb_pipeout(urb->pipe)); } - /* Set the flag on the last packet */ - if (!(urb->transfer_flags & URB_NO_INTERRUPT)) - td->status |= cpu_to_le32(TD_CTRL_IOC); + /* Set the interrupt-on-completion flag on the last packet. + * A more-or-less typical 4 KB URB (= size of one memory page) + * will require about 3 ms to transfer; that's a little on the + * fast side but not enough to justify delaying an interrupt + * more than 2 or 3 URBs, so we will ignore the URB_NO_INTERRUPT + * flag setting. */ + td->status |= cpu_to_le32(TD_CTRL_IOC); qh = uhci_alloc_qh(uhci, urb->dev); if (!qh) @@ -1786,6 +1780,9 @@ spin_unlock(&uhci->schedule_lock); + /* Wake up anyone waiting for an URB to complete */ + wake_up_all(&uhci->waitqh); + return IRQ_HANDLED; } @@ -2086,6 +2083,8 @@ INIT_LIST_HEAD(&uhci->complete_list); + init_waitqueue_head(&uhci->waitqh); + uhci->fl = dma_alloc_coherent(uhci_dev(uhci), sizeof(*uhci->fl), &dma_handle, 0); if (!uhci->fl) { @@ -2296,6 +2295,9 @@ uhci_free_pending_qhs(uhci); uhci_free_pending_tds(uhci); spin_unlock_irq(&uhci->schedule_lock); + + /* Wake up anyone waiting for an URB to complete */ + wake_up_all(&uhci->waitqh); release_uhci(uhci); } @@ -2361,6 +2363,46 @@ kfree(hcd_to_uhci(hcd)); } +/* Are there any URBs for a particular device/endpoint on a given list? */ +static int urbs_for_ep_list(struct list_head *head, + struct hcd_dev *hdev, int ep) +{ + struct urb_priv *urbp; + + list_for_each_entry(urbp, head, urb_list) { + struct urb *urb = urbp->urb; + + if (hdev == urb->dev->hcpriv && ep == + (usb_pipeendpoint(urb->pipe) | + usb_pipein(urb->pipe))) + return 1; + } + return 0; +} + +/* Are there any URBs for a particular device/endpoint? */ +static int urbs_for_ep(struct uhci_hcd *uhci, struct hcd_dev *hdev, int ep) +{ + int rc; + + spin_lock_irq(&uhci->schedule_lock); + rc = (urbs_for_ep_list(&uhci->urb_list, hdev, ep) || + urbs_for_ep_list(&uhci->complete_list, hdev, ep) || + urbs_for_ep_list(&uhci->urb_remove_list, hdev, ep)); + spin_unlock_irq(&uhci->schedule_lock); + return rc; +} + +/* Wait until all the URBs for a particular device/endpoint are gone */ +static void uhci_hcd_endpoint_disable(struct usb_hcd *hcd, + struct hcd_dev *hdev, int endpoint) +{ + struct uhci_hcd *uhci = hcd_to_uhci(hcd); + + wait_event_interruptible(uhci->waitqh, + !urbs_for_ep(uhci, hdev, endpoint)); +} + static int uhci_hcd_get_frame_number(struct usb_hcd *hcd) { return uhci_get_current_frame_number(hcd_to_uhci(hcd)); @@ -2390,6 +2432,7 @@ .urb_enqueue = uhci_urb_enqueue, .urb_dequeue = uhci_urb_dequeue, + .endpoint_disable = uhci_hcd_endpoint_disable, .get_frame_number = uhci_hcd_get_frame_number, .hub_status_data = uhci_hub_status_data, diff -Nru a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h --- a/drivers/usb/host/uhci-hcd.h Sun Apr 25 23:06:52 2004 +++ b/drivers/usb/host/uhci-hcd.h Sun Apr 25 23:06:52 2004 @@ -80,7 +80,7 @@ #define CAN_SCHEDULE_FRAMES 1000 /* how far future frames can be scheduled */ struct uhci_frame_list { - __u32 frame[UHCI_NUMFRAMES]; + u32 frame[UHCI_NUMFRAMES]; void *frame_cpu[UHCI_NUMFRAMES]; @@ -105,8 +105,8 @@ */ struct uhci_qh { /* Hardware fields */ - __u32 link; /* Next queue */ - __u32 element; /* Queue element pointer */ + u32 link; /* Next queue */ + u32 element; /* Queue element pointer */ /* Software fields */ dma_addr_t dma_handle; @@ -185,10 +185,10 @@ */ struct uhci_td { /* Hardware fields */ - __u32 link; - __u32 status; - __u32 token; - __u32 buffer; + u32 link; + u32 status; + u32 token; + u32 buffer; /* Software fields */ dma_addr_t dma_handle; @@ -370,6 +370,8 @@ int rh_numports; struct timer_list stall_timer; + + wait_queue_head_t waitqh; /* endpoint_disable waiters */ }; struct urb_priv { diff -Nru a/drivers/usb/media/ibmcam.c b/drivers/usb/media/ibmcam.c --- a/drivers/usb/media/ibmcam.c Sun Apr 25 23:06:52 2004 +++ b/drivers/usb/media/ibmcam.c Sun Apr 25 23:06:52 2004 @@ -3647,7 +3647,7 @@ { struct usb_device *dev = interface_to_usbdev(intf); struct uvd *uvd = NULL; - int i, nas, model=0, canvasX=0, canvasY=0; + int ix, i, nas, model=0, canvasX=0, canvasY=0; int actInterface=-1, inactInterface=-1, maxPS=0; __u8 ifnum = intf->altsetting->desc.bInterfaceNumber; unsigned char video_ep = 0; @@ -3718,7 +3718,7 @@ } while (0); /* Validate found interface: must have one ISO endpoint */ - nas = dev->actconfig->interface[ifnum]->num_altsetting; + nas = intf->num_altsetting; if (debug > 0) info("Number of alternate settings=%d.", nas); if (nas < 2) { @@ -3726,11 +3726,12 @@ return -ENODEV; } /* Validate all alternate settings */ - for (i=0; i < nas; i++) { + for (ix=0; ix < nas; ix++) { const struct usb_host_interface *interface; const struct usb_endpoint_descriptor *endpoint; - interface = &dev->actconfig->interface[ifnum]->altsetting[i]; + interface = &intf->altsetting[ix]; + i = interface->desc.bAlternateSetting; if (interface->desc.bNumEndpoints != 1) { err("Interface %d. has %u. endpoints!", ifnum, (unsigned)(interface->desc.bNumEndpoints)); diff -Nru a/drivers/usb/media/konicawc.c b/drivers/usb/media/konicawc.c --- a/drivers/usb/media/konicawc.c Sun Apr 25 23:06:52 2004 +++ b/drivers/usb/media/konicawc.c Sun Apr 25 23:06:52 2004 @@ -381,9 +381,15 @@ int i, errFlag; struct konicawc *cam = (struct konicawc *)uvd->user_data; int pktsz; - struct usb_host_interface *interface; + struct usb_interface *intf; + struct usb_host_interface *interface = NULL; - interface = &dev->actconfig->interface[uvd->iface]->altsetting[spd_to_iface[cam->speed]]; + intf = usb_ifnum_to_if(dev, uvd->iface); + if (intf) + interface = usb_altnum_to_altsetting(intf, + spd_to_iface[cam->speed]); + if (!interface) + return -ENXIO; pktsz = interface->endpoint[1].desc.wMaxPacketSize; DEBUG(1, "pktsz = %d", pktsz); if (!CAMERA_IS_OPERATIONAL(uvd)) { @@ -721,7 +727,7 @@ { struct usb_device *dev = interface_to_usbdev(intf); struct uvd *uvd = NULL; - int i, nas; + int ix, i, nas; int actInterface=-1, inactInterface=-1, maxPS=0; unsigned char video_ep = 0; @@ -741,11 +747,12 @@ return -ENODEV; } /* Validate all alternate settings */ - for (i=0; i < nas; i++) { + for (ix=0; ix < nas; ix++) { const struct usb_host_interface *interface; const struct usb_endpoint_descriptor *endpoint; - interface = &intf->altsetting[i]; + interface = &intf->altsetting[ix]; + i = interface->desc.bAlternateSetting; if (interface->desc.bNumEndpoints != 2) { err("Interface %d. has %u. endpoints!", interface->desc.bInterfaceNumber, diff -Nru a/drivers/usb/media/ov511.c b/drivers/usb/media/ov511.c --- a/drivers/usb/media/ov511.c Sun Apr 25 23:06:52 2004 +++ b/drivers/usb/media/ov511.c Sun Apr 25 23:06:52 2004 @@ -5603,8 +5603,16 @@ if (ov->bridge == BRG_OV518) { - struct usb_interface *ifp = ov->dev->config[0].interface[0]; - __u16 mxps = ifp->altsetting[7].endpoint[0].desc.wMaxPacketSize; + struct usb_interface *ifp; + struct usb_host_interface *alt; + __u16 mxps = 0; + + ifp = usb_ifnum_to_if(ov->dev, 0); + if (ifp) { + alt = usb_altnum_to_altsetting(ifp, 7); + if (alt) + mxps = alt->endpoint[0].desc.wMaxPacketSize; + } /* Some OV518s have packet numbering by default, some don't */ if (mxps == 897) @@ -5805,7 +5813,7 @@ if (dev->descriptor.bNumConfigurations != 1) return -ENODEV; - idesc = &intf->altsetting[0].desc; + idesc = &intf->cur_altsetting->desc; if (idesc->bInterfaceClass != 0xFF) return -ENODEV; diff -Nru a/drivers/usb/media/pwc-if.c b/drivers/usb/media/pwc-if.c --- a/drivers/usb/media/pwc-if.c Sun Apr 25 23:06:52 2004 +++ b/drivers/usb/media/pwc-if.c Sun Apr 25 23:06:52 2004 @@ -789,7 +789,8 @@ struct urb *urb; int i, j, ret; - struct usb_host_interface *idesc; + struct usb_interface *intf; + struct usb_host_interface *idesc = NULL; if (pdev == NULL) return -EFAULT; @@ -801,7 +802,9 @@ /* Get the current alternate interface, adjust packet size */ if (!udev->actconfig) return -EFAULT; - idesc = &udev->actconfig->interface[0]->altsetting[pdev->valternate]; + intf = usb_ifnum_to_if(udev, 0); + if (intf) + idesc = usb_altnum_to_altsetting(intf, pdev->valternate); if (!idesc) return -EFAULT; diff -Nru a/drivers/usb/media/se401.c b/drivers/usb/media/se401.c --- a/drivers/usb/media/se401.c Sun Apr 25 23:06:52 2004 +++ b/drivers/usb/media/se401.c Sun Apr 25 23:06:52 2004 @@ -1326,7 +1326,7 @@ if (dev->descriptor.bNumConfigurations != 1) return -ENODEV; - interface = &intf->altsetting[0].desc; + interface = &intf->cur_altsetting->desc; /* Is it an se401? */ if (dev->descriptor.idVendor == 0x03e8 && diff -Nru a/drivers/usb/media/ultracam.c b/drivers/usb/media/ultracam.c --- a/drivers/usb/media/ultracam.c Sun Apr 25 23:06:52 2004 +++ b/drivers/usb/media/ultracam.c Sun Apr 25 23:06:52 2004 @@ -513,7 +513,7 @@ { struct usb_device *dev = interface_to_usbdev(intf); struct uvd *uvd = NULL; - int i, nas; + int ix, i, nas; int actInterface=-1, inactInterface=-1, maxPS=0; unsigned char video_ep = 0; @@ -540,11 +540,12 @@ return -ENODEV; } /* Validate all alternate settings */ - for (i=0; i < nas; i++) { + for (ix=0; ix < nas; ix++) { const struct usb_host_interface *interface; const struct usb_endpoint_descriptor *endpoint; - interface = &intf->altsetting[i]; + interface = &intf->altsetting[ix]; + i = interface->desc.bAlternateSetting; if (interface->desc.bNumEndpoints != 1) { err("Interface %d. has %u. endpoints!", interface->desc.bInterfaceNumber, diff -Nru a/drivers/usb/media/vicam.c b/drivers/usb/media/vicam.c --- a/drivers/usb/media/vicam.c Sun Apr 25 23:06:52 2004 +++ b/drivers/usb/media/vicam.c Sun Apr 25 23:06:52 2004 @@ -1303,7 +1303,7 @@ printk(KERN_INFO "ViCam based webcam connected\n"); - interface = &intf->altsetting[0]; + interface = intf->cur_altsetting; DBG(KERN_DEBUG "Interface %d. has %u. endpoints!\n", interface->desc.bInterfaceNumber, (unsigned) (interface->desc.bNumEndpoints)); diff -Nru a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c --- a/drivers/usb/misc/legousbtower.c Sun Apr 25 23:06:52 2004 +++ b/drivers/usb/misc/legousbtower.c Sun Apr 25 23:06:52 2004 @@ -704,7 +704,7 @@ dev->interrupt_out_urb = NULL; - iface_desc = &interface->altsetting[0]; + iface_desc = interface->cur_altsetting; /* set up the endpoint information */ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { diff -Nru a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c --- a/drivers/usb/misc/usbtest.c Sun Apr 25 23:06:52 2004 +++ b/drivers/usb/misc/usbtest.c Sun Apr 25 23:06:52 2004 @@ -802,6 +802,7 @@ switch (status) { case -EINPROGRESS: case -EBUSY: + case -EIDRM: continue; default: dbg ("urb unlink --> %d", status); @@ -1038,8 +1039,6 @@ if (!status) status = usb_submit_urb (urb, SLAB_ATOMIC); if (status) { - if (status == -ECONNRESET || status == -ENOENT) - status = 0; urb->status = status; complete ((struct completion *) urb->context); } @@ -1077,8 +1076,9 @@ wait_ms (jiffies % (2 * INTERRUPT_RATE)); retry: retval = usb_unlink_urb (urb); - if (retval == -EBUSY) { + if (retval == -EBUSY || retval == -EIDRM) { /* we can't unlink urbs while they're completing. + * or if they've completed, and we haven't resubmitted. * "normal" drivers would prevent resubmission, but * since we're testing unlink paths, we can't. */ diff -Nru a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c --- a/drivers/usb/misc/uss720.c Sun Apr 25 23:06:52 2004 +++ b/drivers/usb/misc/uss720.c Sun Apr 25 23:06:52 2004 @@ -553,7 +553,7 @@ i = usb_set_interface(usbdev, intf->altsetting->desc.bInterfaceNumber, 2); printk(KERN_DEBUG "uss720: set inteface result %d\n", i); - interface = &intf->altsetting[2]; + interface = intf->cur_altsetting; /* * Allocate parport interface diff -Nru a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c --- a/drivers/usb/net/usbnet.c Sun Apr 25 23:06:52 2004 +++ b/drivers/usb/net/usbnet.c Sun Apr 25 23:06:52 2004 @@ -928,8 +928,8 @@ */ static int generic_cdc_bind (struct usbnet *dev, struct usb_interface *intf) { - u8 *buf = intf->altsetting->extra; - int len = intf->altsetting->extralen; + u8 *buf = intf->cur_altsetting->extra; + int len = intf->cur_altsetting->extralen; struct usb_interface_descriptor *d; struct cdc_state *info = (void *) &dev->data; int status; @@ -955,7 +955,7 @@ /* this assumes that if there's a non-RNDIS vendor variant * of cdc-acm, it'll fail RNDIS requests cleanly. */ - rndis = (intf->altsetting->desc.bInterfaceProtocol == 0xff); + rndis = (intf->cur_altsetting->desc.bInterfaceProtocol == 0xff); memset (info, 0, sizeof *info); info->control = intf; @@ -1025,7 +1025,7 @@ } /* a data interface altsetting does the real i/o */ - d = &info->data->altsetting->desc; + d = &info->data->cur_altsetting->desc; if (d->bInterfaceClass != USB_CLASS_CDC_DATA) { dev_dbg (&intf->dev, "slave class %u\n", d->bInterfaceClass); diff -Nru a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h --- a/drivers/usb/storage/unusual_devs.h Sun Apr 25 23:06:52 2004 +++ b/drivers/usb/storage/unusual_devs.h Sun Apr 25 23:06:52 2004 @@ -438,22 +438,6 @@ US_FL_SINGLE_LUN ), #endif -/* Following three Minolta cameras reported by Martin Pool - * . Originally discovered by Kedar Petankar, - * Matthew Geier, Mikael Lofj"ard, Marcel de Boer. - */ -UNUSUAL_DEV( 0x0686, 0x4006, 0x0001, 0x0001, - "Minolta", - "DiMAGE 7", - US_SC_SCSI, US_PR_DEVICE, NULL, - 0 ), - -UNUSUAL_DEV( 0x0686, 0x400f, 0x0001, 0x0001, - "Minolta", - "DiMAGE 7Hi", - US_SC_SCSI, US_PR_DEVICE, NULL, - 0 ), - /* Submitted by Benny Sjostrand */ UNUSUAL_DEV( 0x0686, 0x4011, 0x0001, 0x0001, "Minolta", @@ -688,7 +672,7 @@ UNUSUAL_DEV( 0x0a16, 0x8888, 0x0100, 0x0100, "IBM", "IBM USB Memory Key", - US_SC_SCSI, US_PR_BULK, NULL, + US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY ), /* This Pentax still camera is not conformant diff -Nru a/include/linux/usbdevice_fs.h b/include/linux/usbdevice_fs.h --- a/include/linux/usbdevice_fs.h Sun Apr 25 23:06:52 2004 +++ b/include/linux/usbdevice_fs.h Sun Apr 25 23:06:52 2004 @@ -154,7 +154,6 @@ struct dev_state { struct list_head list; /* state list */ - struct rw_semaphore devsem; /* protects modifications to dev (dev == NULL indicating disconnect) */ struct usb_device *dev; struct file *file; spinlock_t lock; /* protects the async urb lists */