bk://kernel.bkbits.net/gregkh/linux/usb-2.6
stern@rowland.harvard.edu|ChangeSet|20040702225747|56493 stern

# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2004/07/03 13:36:37-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
# 
# MAINTAINERS
#   2004/07/03 13:36:33-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/07/02 22:36:07-07: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/07/02 22:36:04-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/storage/scsiglue.c
#   2004/07/02 22:36:04-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/core/usb.c
#   2004/07/02 22:36:04-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/core/message.c
#   2004/07/02 22:36:04-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/core/devio.c
#   2004/07/02 22:36:04-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/07/02 15:33:56-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
# 
# ChangeSet
#   2004/07/02 15:57:47-07:00 stern@rowland.harvard.edu 
#   [PATCH] USB: Remove hub's children upon unbinding
#   
#   This patch fixes a logical hole in the hub driver.  It's possible for the
#   driver to be unbound from a hub without physically unplugging the hub.
#   For example, writing 0 into the bConfigurationValue attribute file will
#   have this effect.  When this happens, we need to make sure that all the
#   child devices of the hub are logically disconnected and their ports
#   disabled.
#   
#   That's what this patch does.  It's a little bit tricky because we can't
#   simply call usb_disconnect() from within the hub driver's disconnect()
#   routine.  While that routine is running it holds the usb bus writelock,
#   but usb_disconnect() would try to acquire it again.  Instead
#   schedule_work() is used, so after a brief delay the children will be
#   removed.
#   
#   Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
#   Signed-off-by: Greg Kroah-Hartman <greg@kroah.com>
# 
# drivers/usb/core/hub.c
#   2004/07/01 07:53:20-07:00 stern@rowland.harvard.edu +41 -2
#   USB: Remove hub's children upon unbinding
# 
# ChangeSet
#   2004/07/02 15:56:49-07:00 stern@rowland.harvard.edu 
#   [PATCH] USB: Store pointer to usb_device in private hub structure
#   
#   This patch adds a pointer to the hub's usb_device into the usb_hub private
#   structure.  It's a small change, and permits a small amount of
#   simplification in a few spots, i.e., avoid calling interface_to_usbdev().
#   This doesn't really do much in itself, but it's a prerequisite for the
#   next patch.  (A situation arises where we can't use the interface pointer
#   to find the usb_device because the interface might not exist.)
#   
#   Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
#   Signed-off-by: Greg Kroah-Hartman <greg@kroah.com>
# 
# drivers/usb/core/hub.h
#   2004/07/01 04:48:09-07:00 stern@rowland.harvard.edu +1 -0
#   USB: Store pointer to usb_device in private hub structure
# 
# drivers/usb/core/hub.c
#   2004/07/01 07:26:05-07:00 stern@rowland.harvard.edu +17 -18
#   USB: Store pointer to usb_device in private hub structure
# 
# ChangeSet
#   2004/07/02 15:54:11-07:00 stern@rowland.harvard.edu 
#   [PATCH] USB: Disallow probing etc. for suspended devices
#   
#   One of the few points from the recent discussion that all participants
#   agreed on was that we should not allow probing or config changes to be
#   attempted on suspended devices.  This patch implements that policy, and it
#   also prevents attempts to change altsettings.  That's just for
#   consistency's sake; even without the patch an attempted altsetting change
#   on a suspended device would simply fail without doing any harm.  By
#   contrast, a configuration change would unbind all the existing drivers
#   before encountering an error, something we don't want to happen.
#   
#   Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
#   Signed-off-by: Greg Kroah-Hartman <greg@kroah.com>
# 
# drivers/usb/core/usb.c
#   2004/06/30 06:44:26-07:00 stern@rowland.harvard.edu +2 -0
#   USB: Disallow probing etc. for suspended devices
# 
# drivers/usb/core/message.c
#   2004/06/30 06:48:12-07:00 stern@rowland.harvard.edu +9 -0
#   USB: Disallow probing etc. for suspended devices
# 
# include/linux/pci_ids.h
#   2004/07/02 15:33:52-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# MAINTAINERS
#   2004/07/02 15:33:52-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/07/02 15:25:25-07:00 stern@rowland.harvard.edu 
#   [PATCH] USB: Don't ask for string descriptor lengths
#   
#   Okay, here's a revised patch (as332b).  This tries first to ask for 255
#   bytes, and if that fails then it asks for the length and the full
#   descriptor.  Hopefully nobody will object to applying this version...
#   
#   You know, it occurs to me that the have_langid field in usb_device could
#   easily be eliminated.  Just set string_langid to -1 during initialization
#   and test for whether or not it is >= 0.  I'll do that some other time.
#   
#   
#   Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
#   Signed-off-by: Greg Kroah-Hartman <greg@kroah.com>
# 
# drivers/usb/core/message.c
#   2004/06/25 08:04:06-07:00 stern@rowland.harvard.edu +121 -101
#   USB: Don't ask for string descriptor lengths
# 
# ChangeSet
#   2004/07/02 15:24:44-07:00 stern@rowland.harvard.edu 
#   [PATCH] USB: Don't track endpoint halts in usbcore
#   
#   The current mechanism for keeping track of which endpoints in a device are
#   halted is both flawed and unnecessary.  It's flawed because devices are
#   free to change the endpoint status whenever they want without telling us,
#   and it's unnecessary because an URB submitted for a halted endpoint will
#   quickly receive an error indication.
#   
#   This patch removes the code associated with tracking halts: the halted[]
#   member of usb_device, the usb_endpoint_halt, usb_endpoint_halted, and
#   usb_endpoint_running macros, all the places where they are used or
#   checked, and the places in the host controller drivers where they get set.
#   
#   This is part of my ongoing program for cleaning up usbcore.  Please apply.
#   
#   
#   Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
#   Signed-off-by: Greg Kroah-Hartman <greg@kroah.com>
# 
# include/linux/usb.h
#   2004/06/24 09:44:16-07:00 stern@rowland.harvard.edu +0 -6
#   USB: Don't track endpoint halts in usbcore
# 
# drivers/usb/storage/transport.c
#   2004/06/24 09:44:16-07:00 stern@rowland.harvard.edu +1 -3
#   USB: Don't track endpoint halts in usbcore
# 
# drivers/usb/image/microtek.c
#   2004/06/24 09:44:16-07:00 stern@rowland.harvard.edu +2 -2
#   USB: Don't track endpoint halts in usbcore
# 
# drivers/usb/host/uhci-hcd.c
#   2004/06/24 09:44:16-07:00 stern@rowland.harvard.edu +0 -4
#   USB: Don't track endpoint halts in usbcore
# 
# drivers/usb/host/ohci-q.c
#   2004/06/24 09:44:16-07:00 stern@rowland.harvard.edu +0 -6
#   USB: Don't track endpoint halts in usbcore
# 
# drivers/usb/host/hc_simple.c
#   2004/06/24 09:44:15-07:00 stern@rowland.harvard.edu +0 -5
#   USB: Don't track endpoint halts in usbcore
# 
# drivers/usb/host/ehci-q.c
#   2004/06/24 09:44:16-07:00 stern@rowland.harvard.edu +2 -10
#   USB: Don't track endpoint halts in usbcore
# 
# drivers/usb/core/urb.c
#   2004/06/24 09:44:16-07:00 stern@rowland.harvard.edu +0 -7
#   USB: Don't track endpoint halts in usbcore
# 
# drivers/usb/core/message.c
#   2004/06/24 09:44:15-07:00 stern@rowland.harvard.edu +7 -17
#   USB: Don't track endpoint halts in usbcore
# 
# drivers/usb/core/hub.c
#   2004/06/24 09:44:16-07:00 stern@rowland.harvard.edu +1 -5
#   USB: Don't track endpoint halts in usbcore
# 
# drivers/usb/core/hcd.h
#   2004/06/24 09:44:16-07:00 stern@rowland.harvard.edu +0 -2
#   USB: Don't track endpoint halts in usbcore
# 
# drivers/usb/core/hcd.c
#   2004/06/24 09:44:16-07:00 stern@rowland.harvard.edu +2 -5
#   USB: Don't track endpoint halts in usbcore
# 
# drivers/usb/core/devices.c
#   2004/06/24 09:44:16-07:00 stern@rowland.harvard.edu +1 -2
#   USB: Don't track endpoint halts in usbcore
# 
# drivers/isdn/hisax/st5481_usb.c
#   2004/06/24 09:44:15-07:00 stern@rowland.harvard.edu +0 -3
#   USB: Don't track endpoint halts in usbcore
# 
# ChangeSet
#   2004/07/02 15:23:56-07:00 stern@rowland.harvard.edu 
#   [PATCH] USB: Implement usb_lock_device_for_reset()
#   
#   This patch creates a special locking routine intended specifically for use
#   when calling usb_reset_device().  A special routine like this is needed to
#   avoid deadlocks with disconnect().  Symbolically:
#   
#   	Khubd				Driver
#   	-----				------
#   					Wants to reset a device, so calls
#   					its own do_reset() function
#   	Receives connect-change
#   	notification and calls
#   	usb_disconnect()
#   
#   	Locks the device and calls
#   	driver->disconnect()
#   					do_reset() tries to lock the
#   					device for the reset, and blocks
#   	disconnect() can't return
#   	until do_reset() is finished
#   
#   One simple-minded way out would be for the driver's do_reset routine to
#   use usb_trylock_device().  I don't like this because it will fail if the
#   device happens to be locked for some innocuous reason, like somebody
#   reading its entry in /proc/bus/usb/devices.
#   
#   Instead, usb_lock_device_for_reset() calls usb_trylock_device()
#   repeatedly, in a polling loop.  It is careful to check that the device
#   state isn't NOTATTACHED and that the driver's interface isn't being
#   unbound; this will allow the lock-and-reset sequence to fail in scenarios
#   like the one above.
#   
#   For the new routine to be able to tell when an interface is being unbound,
#   I had to add an additional field to struct usb_interface.  It's a simple
#   enumeration with four possible values:
#   
#   	USB_INTERFACE_UNBOUND, USB_INTERFACE_BINDING,
#   	USB_INTERFACE_BOUND, USB_INTERFACE_UNBINDING
#   
#   The extra overhead of the new field is not large enough to matter.
#   
#   A quick summary:
#   
#   	Rename __usb_reset_device to usb_reset_device and get rid of
#   	the alternate entry point.
#   
#   	Notify the HCD that endpoint-0's maxpacket size may change
#   	during a device reset (should have been written earlier).
#   
#   	Add the new usb_interface_condition enumeration field to
#   	struct usb_interface.
#   
#   	Set the new field appropriately as interfaces are bound,
#   	unbound, claimed, and released.
#   
#   	Add usb_lock_device_for_reset().
#   
#   	Change the usb-storage, microtek, and stir4200 IRDA drivers
#   	to make them use the new locking routine.
#   
#   With this patch applied, and using an altered gadget driver that forces
#   usb-storage to request a device reset, I've been able to go through a
#   large number of different tests successfully.  Reset during probe(),
#   reset after probe(), disconnect during reset(), reset with device
#   descriptor changing...  They all work beautifully.
#   
#   Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
#   Signed-off-by: Greg Kroah-Hartman <greg@kroah.com>
# 
# include/linux/usb.h
#   2004/06/24 07:09:11-07:00 stern@rowland.harvard.edu +13 -2
#   USB: Implement usb_lock_device_for_reset()
# 
# drivers/usb/storage/scsiglue.c
#   2004/06/24 07:09:11-07:00 stern@rowland.harvard.edu +11 -3
#   USB: Implement usb_lock_device_for_reset()
# 
# drivers/usb/image/microtek.h
#   2004/06/24 07:09:11-07:00 stern@rowland.harvard.edu +1 -0
#   USB: Implement usb_lock_device_for_reset()
# 
# drivers/usb/image/microtek.c
#   2004/06/24 07:09:11-07:00 stern@rowland.harvard.edu +9 -2
#   USB: Implement usb_lock_device_for_reset()
# 
# drivers/usb/core/usb.c
#   2004/06/24 07:09:11-07:00 stern@rowland.harvard.edu +53 -0
#   USB: Implement usb_lock_device_for_reset()
# 
# drivers/usb/core/hub.c
#   2004/06/24 07:09:11-07:00 stern@rowland.harvard.edu +10 -13
#   USB: Implement usb_lock_device_for_reset()
# 
# drivers/usb/core/devio.c
#   2004/06/24 07:09:11-07:00 stern@rowland.harvard.edu +1 -1
#   USB: Implement usb_lock_device_for_reset()
# 
# drivers/net/irda/stir4200.c
#   2004/06/24 07:09:11-07:00 stern@rowland.harvard.edu +10 -0
#   USB: Implement usb_lock_device_for_reset()
# 
# ChangeSet
#   2004/07/02 15:22:54-07:00 stern@rowland.harvard.edu 
#   [PATCH] USB: Implement usb_lock_device() and friends
#   
#   This patch plugs a major hole in USB device locking.  Whenever a new
#   driver is loaded and the matching unbound interfaces are probed, no
#   devices are locked!  Similarly, when a driver is unloaded and its
#   interfaces are unbound, nothing is locked.
#   
#   The patch fixes the problem by introducing a new rwsem and encapsulating
#   the locking procedures.  To lock a single device, the new routine
#   usb_lock_device() gets a readlock on the rwsem and a lock on the device's
#   ->serialize.  When drivers are loaded or removed, all devices are
#   effectively locked by getting a writelock on the rwsem.  The rwsem is
#   also writelocked in one other oddball circumstance: when telling the
#   driver-model core to reprobe all the unbound interfaces on a bus.
#   
#   Details of the patch:
#   
#   	Implement usb_lock_device(), usb_unlock_device(),
#   	usb_lock_all_devices(), usb_unlock_all_devices(), and
#   	usb_trylock_device().
#   
#   	Call usb_(un)lock_all_devices() when registering and
#   	deregistering USB drivers and when calling bus_rescan_devices().
#   
#   	Convert all existing places that access usbdev->serialize
#   	directly to make them call the appropriate locking routine.
#   
#   	Add comments warning about the need to use the new routines,
#   	and change the terminology in existing comments to talk about
#   	locking a device rather than owning usbdev->serialize.
#   
#   	Add proper locking to usb_find_device() and match_device(),
#   	to protect against topology changes while scanning the
#   	device tree.
#   
#   With this change, the USB device locking model is almost complete.  There
#   remains only the need for appropriate locking for routines that call
#   usb_reset_device().  That patch will come next.
#   
#   
#   Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
#   Signed-off-by: Greg Kroah-Hartman <greg@kroah.com>
# 
# include/linux/usb.h
#   2004/06/24 03:41:12-07:00 stern@rowland.harvard.edu +16 -0
#   USB: Implement usb_lock_device() and friends
# 
# drivers/usb/host/ohci-pci.c
#   2004/06/24 03:41:12-07:00 stern@rowland.harvard.edu +4 -4
#   USB: Implement usb_lock_device() and friends
# 
# drivers/usb/host/ohci-hub.c
#   2004/06/24 03:41:12-07:00 stern@rowland.harvard.edu +5 -5
#   USB: Implement usb_lock_device() and friends
# 
# drivers/usb/host/ehci-hub.c
#   2004/06/24 03:41:12-07:00 stern@rowland.harvard.edu +1 -1
#   USB: Implement usb_lock_device() and friends
# 
# drivers/usb/core/usb.h
#   2004/06/24 03:41:12-07:00 stern@rowland.harvard.edu +3 -0
#   USB: Implement usb_lock_device() and friends
# 
# drivers/usb/core/usb.c
#   2004/06/24 03:41:12-07:00 stern@rowland.harvard.edu +88 -7
#   USB: Implement usb_lock_device() and friends
# 
# drivers/usb/core/sysfs.c
#   2004/06/24 03:41:12-07:00 stern@rowland.harvard.edu +2 -2
#   USB: Implement usb_lock_device() and friends
# 
# drivers/usb/core/message.c
#   2004/06/24 03:41:12-07:00 stern@rowland.harvard.edu +7 -7
#   USB: Implement usb_lock_device() and friends
# 
# drivers/usb/core/hub.c
#   2004/06/24 03:41:12-07:00 stern@rowland.harvard.edu +7 -7
#   USB: Implement usb_lock_device() and friends
# 
# drivers/usb/core/hcd.c
#   2004/06/24 03:41:12-07:00 stern@rowland.harvard.edu +4 -4
#   USB: Implement usb_lock_device() and friends
# 
# drivers/usb/core/devio.c
#   2004/06/24 03:41:12-07:00 stern@rowland.harvard.edu +13 -9
#   USB: Implement usb_lock_device() and friends
# 
# drivers/usb/core/devices.c
#   2004/06/24 03:41:12-07:00 stern@rowland.harvard.edu +5 -5
#   USB: Implement usb_lock_device() and friends
# 
# ChangeSet
#   2004/07/02 15:22:14-07:00 stern@rowland.harvard.edu 
#   [PATCH] USB: Make hub driver use usb_kill_urb()
#   
#   This is a rerun of as278, updated to match the current source.  It changes
#   the hub driver, replacing calls to synchronous usb_unlink_urb() with
#   usb_kill_urb() and removing the machinery formerly needed to synchronize
#   the status URB handler with the rest of the driver.
#   
#   
#   Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
#   Signed-off-by: Greg Kroah-Hartman <greg@kroah.com>
# 
# drivers/usb/core/hub.h
#   2004/06/23 07:02:05-07:00 stern@rowland.harvard.edu +0 -2
#   USB: Make hub driver use usb_kill_urb()
# 
# drivers/usb/core/hub.c
#   2004/06/23 07:07:26-07:00 stern@rowland.harvard.edu +12 -28
#   USB: Make hub driver use usb_kill_urb()
# 
# ChangeSet
#   2004/07/02 15:21:04-07:00 stern@rowland.harvard.edu 
#   [PATCH] USB: Add usb_kill_urb()
#   
#   This patch is a slightly revised version of as277c, updated to match the
#   current source.  The only difference from the older version is that this
#   makes urb->use_count into an atomic_t, to avoid the overhead of an extra
#   locking step each time an URB is submitted and given back.  The important
#   features of this patch are:
#   
#   	-EPERM added to Documentation/usb/error-codes.txt.
#   
#   	Failure to use URB_ASYNC_UNLINK with usb_unlink_urb() is
#   	deprecated in the documentation.
#   
#   	New ->reject and ->use_count fields added to struct urb.
#   	The reject field is protected by urb->lock, and locking is
#   	required only in usb_kill_urb() which doesn't have to be fast.
#   
#   	Single wait_queue used for all processes waiting inside
#   	usb_kill_urb().  The wait queue is woken up only when an URB
#   	is given back with ->reject set.
#   
#   	usb_rh_status_dequeue() changed to return int.  It looks like
#   	this function should be declared static; it's not used outside
#   	the hcd.c file.
#   
#   	Prototype for unlink_urb() in struct usb_operations is changed
#   	to include a status code argument.  This is necessary so that
#   	the different unlink paths can return -ENOENT and -ECONNRESET
#   	as appropriate.
#   
#   	Support for synchronous usb_unlink_urb() has been removed;
#   	such calls are passed to usb_kill_urb().
#   
#   	Kerneldoc for usb_unlink_urb() is updated.
#   
#   	usb_kill_urb() added to urb.c.
#   
#   	hc_simple() host driver is partially updated -- it should
#   	compile but it won't really work right.
#   
#   
#   Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
#   Signed-off-by: Greg Kroah-Hartman <greg@kroah.com>
# 
# include/linux/usb.h
#   2004/06/23 08:00:50-07:00 stern@rowland.harvard.edu +7 -2
#   USB: Add usb_kill_urb()
# 
# drivers/usb/host/hc_simple.c
#   2004/06/23 08:00:50-07:00 stern@rowland.harvard.edu +10 -34
#   USB: Add usb_kill_urb()
# 
# drivers/usb/core/urb.c
#   2004/06/23 08:00:50-07:00 stern@rowland.harvard.edu +56 -18
#   USB: Add usb_kill_urb()
# 
# drivers/usb/core/hcd.h
#   2004/06/23 08:00:50-07:00 stern@rowland.harvard.edu +3 -2
#   USB: Add usb_kill_urb()
# 
# drivers/usb/core/hcd.c
#   2004/06/23 08:00:50-07:00 stern@rowland.harvard.edu +43 -96
#   USB: Add usb_kill_urb()
# 
# Documentation/usb/error-codes.txt
#   2004/06/23 08:00:50-07:00 stern@rowland.harvard.edu +2 -0
#   USB: Add usb_kill_urb()
# 
# ChangeSet
#   2004/07/01 01:50:59-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
# 
# include/linux/pci_ids.h
#   2004/07/01 01:50:55-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/core/usb.c
#   2004/07/01 01:50:55-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/core/message.c
#   2004/07/01 01:50:55-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/core/devio.c
#   2004/07/01 01:50:55-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/06/30 11:38:35-07:00 akpm@bix.(none) 
#   Merge bk://kernel.bkbits.net/gregkh/linux/usb-2.6
#   into bix.(none):/usr/src/bk-usb
# 
# drivers/usb/input/hid-core.c
#   2004/06/30 11:38:31-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/06/30 10:48:26-07:00 greg@kroah.com 
#   [PATCH] USB: add 3 Phidget device ids to the HID blacklist.
# 
# drivers/usb/input/hid-core.c
#   2004/06/30 10:25:19-07:00 greg@kroah.com +8 -0
#   USB: add 3 Phidget device ids to the HID blacklist.
# 
# ChangeSet
#   2004/06/29 21:31:17-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
# 
# fs/aio.c
#   2004/06/29 21:31:13-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# MAINTAINERS
#   2004/06/29 21:31:13-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# CREDITS
#   2004/06/29 21:31:13-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/06/28 19:30:55-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
# 
# fs/aio.c
#   2004/06/28 19:30:52-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/06/28 00:43:18-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
# 
# arch/ppc/defconfig
#   2004/06/28 00:43:14-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# arch/ia64/defconfig
#   2004/06/28 00:43:14-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/06/24 18:40:41-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
# 
# include/linux/pci_ids.h
#   2004/06/24 18:40:37-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/06/24 13:02:42-07:00 akpm@bix.(none) 
#   Merge bk://kernel.bkbits.net/gregkh/linux/usb-2.6
#   into bix.(none):/usr/src/bk-usb
# 
# drivers/usb/media/pwc-if.c
#   2004/06/24 13:02:39-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/media/Kconfig
#   2004/06/24 13:02:39-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/gadget/ether.c
#   2004/06/24 13:02:39-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/06/24 13:01:44-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
# 
# include/linux/pci_ids.h
#   2004/06/24 13:01:40-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# MAINTAINERS
#   2004/06/24 13:01:40-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# CREDITS
#   2004/06/24 13:01:40-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/06/22 12:28:34-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
# 
# drivers/usb/core/devio.c
#   2004/06/22 12:28:30-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# MAINTAINERS
#   2004/06/22 12:28:30-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/06/20 23:36:26-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
# 
# CREDITS
#   2004/06/20 23:36:01-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/06/19 15:38:35-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
# 
# arch/ia64/defconfig
#   2004/06/19 15:38:31-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/06/18 12:32:27-07:00 akpm@bix.(none) 
#   Merge bk://kernel.bkbits.net/gregkh/linux/usb-2.6
#   into bix.(none):/usr/src/bk-usb
# 
# drivers/usb/storage/scsiglue.c
#   2004/06/18 12:32:23-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/media/Kconfig
#   2004/06/18 12:32:23-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/06/18 12:31:30-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
# 
# include/linux/pci_ids.h
#   2004/06/18 12:31:26-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/storage/scsiglue.c
#   2004/06/18 12:31:26-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# MAINTAINERS
#   2004/06/18 12:31:26-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# CREDITS
#   2004/06/18 12:31:26-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/06/15 22:24:54-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
# 
# include/linux/pci_ids.h
#   2004/06/15 22:24:51-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/06/13 11:33:57-07:00 akpm@bix.(none) 
#   Merge bk://kernel.bkbits.net/gregkh/linux/usb-2.6
#   into bix.(none):/usr/src/bk-usb
# 
# drivers/usb/input/hiddev.c
#   2004/06/13 11:33:54-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/core/message.c
#   2004/06/13 11:33:54-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/06/13 11:33:07-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
# 
# MAINTAINERS
#   2004/06/13 11:33:04-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/06/10 13:10:48-07:00 akpm@bix.(none) 
#   Merge bk://kernel.bkbits.net/gregkh/linux/usb-2.6
#   into bix.(none):/usr/src/bk-usb
# 
# drivers/usb/media/pwc-if.c
#   2004/06/10 13:10:45-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/input/hiddev.c
#   2004/06/10 13:10:45-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/input/hid-core.c
#   2004/06/10 13:10:45-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/core/devio.c
#   2004/06/10 13:10:44-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/06/09 12:17:34-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/06/09 12:17:31-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/06/08 22:02:51-07: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/06/08 22:02:48-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/serial/cyberjack.c
#   2004/06/08 22:02:48-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/media/pwc-if.c
#   2004/06/08 22:02:48-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/media/Kconfig
#   2004/06/08 22:02:48-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/gadget/ether.c
#   2004/06/08 22:02:48-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/core/devio.c
#   2004/06/08 22:02:48-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/06/08 12:41:28-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
# 
# include/linux/usb.h
#   2004/06/08 12:41:24-07:00 akpm@bix.(none) +0 -1
#   Auto merged
# 
# drivers/usb/serial/cyberjack.c
#   2004/06/08 12:41:24-07:00 akpm@bix.(none) +0 -6
#   Auto merged
# 
# drivers/usb/media/pwc-if.c
#   2004/06/08 12:41:24-07:00 akpm@bix.(none) +0 -1
#   Auto merged
# 
# drivers/usb/media/Kconfig
#   2004/06/08 12:41:24-07:00 akpm@bix.(none) +0 -1
#   Auto merged
# 
# drivers/usb/core/devio.c
#   2004/06/08 12:41:24-07:00 akpm@bix.(none) +0 -1
#   Auto merged
# 
# ChangeSet
#   2004/06/07 20:07:13-07: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/06/07 20:07:10-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/gadget/ether.c
#   2004/06/07 20:07:10-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/06/07 14:23:17-07:00 akpm@bix.(none) 
#   Merge bk://kernel.bkbits.net/gregkh/linux/usb-2.6
#   into bix.(none):/usr/src/bk-usb
# 
# drivers/usb/gadget/ether.c
#   2004/06/07 14:23:13-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/core/message.c
#   2004/06/07 14:23:13-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/06/07 14:22:27-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
# 
# drivers/usb/input/hiddev.c
#   2004/06/07 14:22:24-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/06/05 17:09:11-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
# 
# MAINTAINERS
#   2004/06/05 17:09:08-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/06/04 02:41:08-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
# 
# drivers/usb/gadget/ether.c
#   2004/06/04 02:41:05-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/06/03 10:45:02-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
# 
# include/linux/pci_ids.h
#   2004/06/03 10:44:58-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/06/02 23:58:29-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/06/02 23:58:25-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/06/02 13:38: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/06/02 13:38:09-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/06/02 13:37:23-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
# 
# include/linux/pci_ids.h
#   2004/06/02 13:37:20-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/06/01 13:57:49-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
# 
# MAINTAINERS
#   2004/06/01 13:57:45-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/05/30 00:23:52-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
# 
# MAINTAINERS
#   2004/05/30 00:23:48-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# CREDITS
#   2004/05/30 00:23:48-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/05/28 17:18:45-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
# 
# include/linux/pci_ids.h
#   2004/05/28 17:18:42-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/05/28 14:16:41-07:00 akpm@bix.(none) 
#   Merge bk://kernel.bkbits.net/gregkh/linux/usb-2.6
#   into bix.(none):/usr/src/bk-usb
# 
# drivers/usb/input/hiddev.c
#   2004/05/28 14:16:37-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/05/28 14:15:52-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
# 
# include/linux/pci_ids.h
#   2004/05/28 14:15:49-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# MAINTAINERS
#   2004/05/28 14:15:48-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/05/25 13:48:31-07:00 akpm@bix.(none) 
#   Merge bk://kernel.bkbits.net/gregkh/linux/usb-2.6
#   into bix.(none):/usr/src/bk-usb
# 
# drivers/usb/input/hiddev.c
#   2004/05/25 13:48:27-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/core/usb.c
#   2004/05/25 13:48:27-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/core/message.c
#   2004/05/25 13:48:27-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/05/25 13:47:38-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
# 
# MAINTAINERS
#   2004/05/25 13:47:34-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/05/24 11:48:01-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
# 
# include/linux/pci_ids.h
#   2004/05/24 11:47:57-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/05/22 23:48:51-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
# 
# include/linux/pci_ids.h
#   2004/05/22 23:48:48-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# MAINTAINERS
#   2004/05/22 23:48:48-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/05/21 19:09:03-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
# 
# arch/ia64/defconfig
#   2004/05/21 19:09:00-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# MAINTAINERS
#   2004/05/21 19:09:00-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/05/19 18:31:55-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
# 
# MAINTAINERS
#   2004/05/19 18:31:52-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/05/19 00:07:04-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
# 
# include/linux/usb.h
#   2004/05/19 00:07:01-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# include/linux/pci_ids.h
#   2004/05/19 00:07:01-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/core/usb.c
#   2004/05/19 00:07:01-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# arch/ppc/defconfig
#   2004/05/19 00:07:01-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# arch/ppc/configs/pmac_defconfig
#   2004/05/19 00:07:01-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# arch/ppc/configs/common_defconfig
#   2004/05/19 00:07:01-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/05/18 14:54:09-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
# 
# include/linux/usb.h
#   2004/05/18 14:54:06-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# include/linux/pci_ids.h
#   2004/05/18 14:54:06-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/input/hid-core.c
#   2004/05/18 14:54:06-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/core/usb.c
#   2004/05/18 14:54:06-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# CREDITS
#   2004/05/18 14:54:06-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/05/16 01:52:25-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
# 
# include/linux/pci_ids.h
#   2004/05/16 01:52:22-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/05/14 21:45:47-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
# 
# include/linux/pci_ids.h
#   2004/05/14 21:45:43-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/05/14 09:41:12-07:00 akpm@bix.(none) 
#   Merge bk://kernel.bkbits.net/gregkh/linux/usb-2.6
#   into bix.(none):/usr/src/bk-usb
# 
# drivers/usb/input/hid-core.c
#   2004/05/14 09:41:09-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/core/usb.c
#   2004/05/14 09:41:09-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/core/message.c
#   2004/05/14 09:41:09-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/05/12 20:32:44-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/inode.c
#   2004/05/12 20:32:41-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# MAINTAINERS
#   2004/05/12 20:32:41-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/05/12 01:26:11-07: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/05/12 01:26:08-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/input/hid-core.c
#   2004/05/12 01:26:08-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/05/12 01:25:17-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
# 
# include/linux/pci_ids.h
#   2004/05/12 01:25:14-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# arch/parisc/configs/c3000_defconfig
#   2004/05/12 01:25:14-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# MAINTAINERS
#   2004/05/12 01:25:14-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/05/05 14:52:58-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/05/05 14:52:55-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/05/05 14:52:11-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
# 
# CREDITS
#   2004/05/05 14:52:08-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/05/04 14:13:11-07: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/05/04 14:13:08-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/05/01 15:23:25-07:00 akpm@bix.(none) 
#   Merge bk://kernel.bkbits.net/gregkh/linux/usb-2.6
#   into bix.(none):/usr/src/bk-usb
# 
# MAINTAINERS
#   2004/05/01 15:23:22-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/04/30 22:06:45-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
# 
# drivers/usb/core/inode.c
#   2004/04/30 22:06:42-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/04/29 16:00:47-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/29 16:00:44-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# MAINTAINERS
#   2004/04/29 16:00:44-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/04/28 13:38:52-07:00 akpm@bix.(none) 
#   Merge bk://kernel.bkbits.net/gregkh/linux/usb-2.6
#   into bix.(none):/usr/src/bk-usb
# 
# drivers/usb/input/hid-core.c
#   2004/04/28 13:38:49-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/04/27 19:39:13-07: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/04/27 19:39:10-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/core/usb.c
#   2004/04/27 19:39:10-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/core/message.c
#   2004/04/27 19:39:10-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/04/26 18:31:48-07: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/04/26 18:31:45-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/core/usb.c
#   2004/04/26 18:31:45-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# 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 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/Documentation/usb/error-codes.txt b/Documentation/usb/error-codes.txt
--- a/Documentation/usb/error-codes.txt	2004-07-04 23:02:39 -07:00
+++ b/Documentation/usb/error-codes.txt	2004-07-04 23:02:39 -07:00
@@ -47,6 +47,8 @@
 -ESHUTDOWN	The host controller has been disabled due to some
 		problem that could not be worked around.
 
+-EPERM		Submission failed because urb->reject was set.
+
 
 **************************************************************************
 *                   Error codes returned by in urb->status               *
diff -Nru a/drivers/isdn/hisax/st5481_usb.c b/drivers/isdn/hisax/st5481_usb.c
--- a/drivers/isdn/hisax/st5481_usb.c	2004-07-04 23:02:39 -07:00
+++ b/drivers/isdn/hisax/st5481_usb.c	2004-07-04 23:02:39 -07:00
@@ -143,9 +143,6 @@
 	if (ctrl_msg->dr.bRequest == USB_REQ_CLEAR_FEATURE) {
 	        /* Special case handling for pipe reset */
 		le16_to_cpus(&ctrl_msg->dr.wIndex);
-		usb_endpoint_running(adapter->usb_dev,
-				     ctrl_msg->dr.wIndex & ~USB_DIR_IN, 
-				     (ctrl_msg->dr.wIndex & USB_DIR_IN) == 0);
 
 		/* toggle is reset on clear */
 		usb_settoggle(adapter->usb_dev, 
diff -Nru a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c
--- a/drivers/net/irda/stir4200.c	2004-07-04 23:02:39 -07:00
+++ b/drivers/net/irda/stir4200.c	2004-07-04 23:02:39 -07:00
@@ -168,6 +168,7 @@
 
 struct stir_cb {
         struct usb_device *usbdev;      /* init: probe_irda */
+	struct usb_interface *usbintf;
         struct net_device *netdev;      /* network layer */
         struct irlap_cb   *irlap;       /* The link layer we are binded to */
         struct net_device_stats stats;	/* network statistics */
@@ -508,6 +509,7 @@
 {
 	int i, err;
 	__u8 mode;
+	int rc;
 
 	for (i = 0; i < ARRAY_SIZE(stir_modes); ++i) {
 		if (speed == stir_modes[i].speed)
@@ -521,7 +523,14 @@
 	pr_debug("speed change from %d to %d\n", stir->speed, speed);
 
 	/* sometimes needed to get chip out of stuck state */
+	rc = usb_lock_device_for_reset(stir->usbdev, stir->usbintf);
+	if (rc < 0) {
+		err = rc;
+		goto out;
+	}
 	err = usb_reset_device(stir->usbdev);
+	if (rc)
+		usb_unlock_device(stir->usbdev);
 	if (err)
 		goto out;
 
@@ -1066,6 +1075,7 @@
 	stir = net->priv;
 	stir->netdev = net;
 	stir->usbdev = dev;
+	stir->usbintf = intf;
 
 	ret = usb_reset_configuration(dev);
 	if (ret != 0) {
diff -Nru a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c
--- a/drivers/usb/core/devices.c	2004-07-04 23:02:39 -07:00
+++ b/drivers/usb/core/devices.c	2004-07-04 23:02:39 -07:00
@@ -283,9 +283,8 @@
 
 /* TBD:
  * 0. TBDs
- * 1. marking active config and ifaces (code lists all, but should mark
+ * 1. marking active interface altsettings (code lists all, but should mark
  *    which ones are active, if any)
- * 2. add <halted> status to each endpoint line
  */
 
 static char *usb_dump_config_descriptor(char *start, char *end, const struct usb_config_descriptor *desc, int active)
@@ -452,7 +451,7 @@
  * nbytes - the maximum number of bytes to write
  * skip_bytes - the number of bytes to skip before writing anything
  * file_offset - the offset into the devices file on completion
- * The caller must own the usbdev->serialize semaphore.
+ * The caller must have locked the device.
  */
 static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, loff_t *skip_bytes, loff_t *file_offset,
 				struct usb_device *usbdev, struct usb_bus *bus, int level, int index, int count)
@@ -556,10 +555,10 @@
 		struct usb_device *childdev = usbdev->children[chix];
 
 		if (childdev) {
-			down(&childdev->serialize);
+			usb_lock_device(childdev);
 			ret = usb_device_dump(buffer, nbytes, skip_bytes, file_offset, childdev,
 					bus, level + 1, chix, ++cnt);
-			up(&childdev->serialize);
+			usb_unlock_device(childdev);
 			if (ret == -EFAULT)
 				return total_written;
 			total_written += ret;
@@ -591,9 +590,9 @@
 		/* recurse through all children of the root hub */
 		if (!bus->root_hub)
 			continue;
-		down(&bus->root_hub->serialize);
+		usb_lock_device(bus->root_hub);
 		ret = usb_device_dump(&buf, &nbytes, &skip_bytes, ppos, bus->root_hub, bus, 0, 0, 0);
-		up(&bus->root_hub->serialize);
+		usb_unlock_device(bus->root_hub);
 		if (ret < 0) {
 			up(&usb_bus_list_lock);
 			return ret;
diff -Nru a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
--- a/drivers/usb/core/devio.c	2004-07-04 23:02:39 -07:00
+++ b/drivers/usb/core/devio.c	2004-07-04 23:02:39 -07:00
@@ -111,7 +111,7 @@
 	int i;
 
 	pos = *ppos;
-	down(&dev->serialize);
+	usb_lock_device(dev);
 	if (!connected(dev)) {
 		ret = -ENODEV;
 		goto err;
@@ -173,7 +173,7 @@
 	}
 
 err:
-	up(&dev->serialize);
+	usb_unlock_device(dev);
 	return ret;
 }
 
@@ -514,7 +514,7 @@
 	struct usb_device *dev = ps->dev;
 	unsigned int ifnum;
 
-	down(&dev->serialize);
+	usb_lock_device(dev);
 	list_del_init(&ps->list);
 
 	if (connected(dev)) {
@@ -523,7 +523,7 @@
 				releaseintf(ps, ifnum);
 		destroy_all_async(ps);
 	}
-	up(&dev->serialize);
+	usb_unlock_device(dev);
 	usb_put_dev(dev);
 	ps->dev = NULL;
 	kfree(ps);
@@ -722,7 +722,7 @@
 
 static int proc_resetdevice(struct dev_state *ps)
 {
-	return __usb_reset_device(ps->dev);
+	return usb_reset_device(ps->dev);
 
 }
 
@@ -1012,9 +1012,9 @@
 			break;
 		if (signal_pending(current))
 			break;
-		up(&dev->serialize);
+		usb_unlock_device(dev);
 		schedule();
-		down(&dev->serialize);
+		usb_lock_device(dev);
 	}
 	remove_wait_queue(&ps->wait, &wait);
 	set_current_state(TASK_RUNNING);
@@ -1137,7 +1137,11 @@
 
 	/* let kernel drivers try to (re)bind to the interface */
 	case USBDEVFS_CONNECT:
+		usb_unlock_device(ps->dev);
+		usb_lock_all_devices();
 		bus_rescan_devices(intf->dev.bus);
+		usb_unlock_all_devices();
+		usb_lock_device(ps->dev);
 		break;
 
 	/* talk directly to the interface's driver */
@@ -1180,9 +1184,9 @@
 
 	if (!(file->f_mode & FMODE_WRITE))
 		return -EPERM;
-	down(&dev->serialize);
+	usb_lock_device(dev);
 	if (!connected(dev)) {
-		up(&dev->serialize);
+		usb_unlock_device(dev);
 		return -ENODEV;
 	}
 
@@ -1282,7 +1286,7 @@
 		ret = proc_ioctl(ps, p);
 		break;
 	}
-	up(&dev->serialize);
+	usb_unlock_device(dev);
 	if (ret >= 0)
 		inode->i_atime = CURRENT_TIME;
 	return ret;
diff -Nru a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
--- a/drivers/usb/core/hcd.c	2004-07-04 23:02:39 -07:00
+++ b/drivers/usb/core/hcd.c	2004-07-04 23:02:39 -07:00
@@ -102,6 +102,9 @@
 /* used when updating hcd data */
 static spinlock_t hcd_data_lock = SPIN_LOCK_UNLOCKED;
 
+/* wait queue for synchronous unlinks */
+DECLARE_WAIT_QUEUE_HEAD(usb_kill_urb_queue);
+
 /*-------------------------------------------------------------------------*/
 
 /*
@@ -569,7 +572,7 @@
 
 /*-------------------------------------------------------------------------*/
 
-void usb_rh_status_dequeue (struct usb_hcd *hcd, struct urb *urb)
+int usb_rh_status_dequeue (struct usb_hcd *hcd, struct urb *urb)
 {
 	unsigned long	flags;
 
@@ -581,6 +584,7 @@
 	urb->hcpriv = NULL;
 	usb_hcd_giveback_urb (hcd, urb, NULL);
 	local_irq_restore (flags);
+	return 0;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -791,9 +795,9 @@
 		return (retval < 0) ? retval : -EMSGSIZE;
 	}
 
-	down (&usb_dev->serialize);
+	usb_lock_device (usb_dev);
 	retval = usb_new_device (usb_dev);
-	up (&usb_dev->serialize);
+	usb_unlock_device (usb_dev);
 	if (retval) {
 		usb_dev->bus->root_hub = NULL;
 		dev_err (parent_dev, "can't register root hub for %s, %d\n",
@@ -1029,7 +1033,6 @@
 static void urb_unlink (struct urb *urb)
 {
 	unsigned long		flags;
-	struct usb_device	*dev;
 
 	/* Release any periodic transfer bandwidth */
 	if (urb->bandwidth)
@@ -1040,9 +1043,8 @@
 
 	spin_lock_irqsave (&hcd_data_lock, flags);
 	list_del_init (&urb->urb_list);
-	dev = urb->dev;
 	spin_unlock_irqrestore (&hcd_data_lock, flags);
-	usb_put_dev (dev);
+	usb_put_dev (urb->dev);
 }
 
 
@@ -1079,23 +1081,28 @@
 	// FIXME:  verify that quiescing hc works right (RH cleans up)
 
 	spin_lock_irqsave (&hcd_data_lock, flags);
-	if (HCD_IS_RUNNING (hcd->state) && hcd->state != USB_STATE_QUIESCING) {
+	if (unlikely (urb->reject))
+		status = -EPERM;
+	else if (HCD_IS_RUNNING (hcd->state) &&
+			hcd->state != USB_STATE_QUIESCING) {
 		usb_get_dev (urb->dev);
 		list_add_tail (&urb->urb_list, &dev->urb_list);
 		status = 0;
-	} else {
-		INIT_LIST_HEAD (&urb->urb_list);
+	} else
 		status = -ESHUTDOWN;
-	}
 	spin_unlock_irqrestore (&hcd_data_lock, flags);
-	if (status)
+	if (status) {
+		INIT_LIST_HEAD (&urb->urb_list);
 		return status;
+	}
 
 	/* increment urb's reference count as part of giving it to the HCD
 	 * (which now controls it).  HCD guarantees that it either returns
 	 * an error or calls giveback(), but not both.
 	 */
 	urb = usb_get_urb (urb);
+	atomic_inc (&urb->use_count);
+
 	if (urb->dev == hcd->self.root_hub) {
 		/* NOTE:  requirement on hub callers (usbfs and the hub
 		 * driver, for now) that URBs' urb->transfer_buffer be
@@ -1132,9 +1139,12 @@
 
 	status = hcd->driver->urb_enqueue (hcd, urb, mem_flags);
 done:
-	if (status) {
-		usb_put_urb (urb);
+	if (unlikely (status)) {
 		urb_unlink (urb);
+		atomic_dec (&urb->use_count);
+		if (urb->reject)
+			wake_up (&usb_kill_urb_queue);
+		usb_put_urb (urb);
 	}
 	return status;
 }
@@ -1157,60 +1167,39 @@
  * soon as practical.  we've already set up the urb's return status,
  * but we can't know if the callback completed already.
  */
-static void
+static int
 unlink1 (struct usb_hcd *hcd, struct urb *urb)
 {
+	int		value;
+
 	if (urb == (struct urb *) hcd->rh_timer.data)
-		usb_rh_status_dequeue (hcd, urb);
+		value = usb_rh_status_dequeue (hcd, urb);
 	else {
-		int		value;
 
-		/* failures "should" be harmless */
+		/* The only reason an HCD might fail this call is if
+		 * it has not yet fully queued the urb to begin with.
+		 * Such failures should be harmless. */
 		value = hcd->driver->urb_dequeue (hcd, urb);
-		if (value != 0)
-			dev_dbg (hcd->self.controller,
-				"dequeue %p --> %d\n",
-				urb, value);
 	}
-}
-
-struct completion_splice {		// modified urb context:
-	/* did we complete? */
-	struct completion	done;
-
-	/* original urb data */
-	usb_complete_t		complete;
-	void			*context;
-};
-
-static void unlink_complete (struct urb *urb, struct pt_regs *regs)
-{
-	struct completion_splice	*splice;
-
-	splice = (struct completion_splice *) urb->context;
 
-	/* issue original completion call */
-	urb->complete = splice->complete;
-	urb->context = splice->context;
-	urb->complete (urb, regs);
-
-	/* then let the synchronous unlink call complete */
-	complete (&splice->done);
+	if (value != 0)
+		dev_dbg (hcd->self.controller, "dequeue %p --> %d\n",
+				urb, value);
+	return value;
 }
 
 /*
- * called in any context; note ASYNC_UNLINK restrictions
+ * called in any context
  *
  * caller guarantees urb won't be recycled till both unlink()
  * and the urb's completion function return
  */
-static int hcd_unlink_urb (struct urb *urb)
+static int hcd_unlink_urb (struct urb *urb, int status)
 {
 	struct hcd_dev			*dev;
 	struct usb_hcd			*hcd = NULL;
 	struct device			*sys = NULL;
 	unsigned long			flags;
-	struct completion_splice	splice;
 	struct list_head		*tmp;
 	int				retval;
 
@@ -1262,8 +1251,6 @@
 
 	/* Any status except -EINPROGRESS means something already started to
 	 * unlink this URB from the hardware.  So there's no more work to do.
-	 *
-	 * FIXME use better explicit urb state
 	 */
 	if (urb->status != -EINPROGRESS) {
 		retval = -EBUSY;
@@ -1281,62 +1268,19 @@
 		hcd->saw_irq = 1;
 	}
 
-	/* maybe set up to block until the urb's completion fires.  the
-	 * lower level hcd code is always async, locking on urb->status
-	 * updates; an intercepted completion unblocks us.
-	 */
-	if (!(urb->transfer_flags & URB_ASYNC_UNLINK)) {
-		if (in_interrupt ()) {
-			dev_dbg (hcd->self.controller, 
-				"non-async unlink in_interrupt");
-			retval = -EWOULDBLOCK;
-			goto done;
-		}
-		/* synchronous unlink: block till we see the completion */
-		init_completion (&splice.done);
-		splice.complete = urb->complete;
-		splice.context = urb->context;
-		urb->complete = unlink_complete;
-		urb->context = &splice;
-		urb->status = -ENOENT;
-	} else {
-		/* asynchronous unlink */
-		urb->status = -ECONNRESET;
-	}
+	urb->status = status;
+
 	spin_unlock (&hcd_data_lock);
 	spin_unlock_irqrestore (&urb->lock, flags);
 
-	// FIXME remove splicing, so this becomes unlink1 (hcd, urb);
-	if (urb == (struct urb *) hcd->rh_timer.data) {
-		usb_rh_status_dequeue (hcd, urb);
-		retval = 0;
-	} else {
-		retval = hcd->driver->urb_dequeue (hcd, urb);
-
-		/* hcds shouldn't really fail these calls, but... */
-		if (retval) {
-			dev_dbg (sys, "dequeue %p --> %d\n", urb, retval);
-			if (!(urb->transfer_flags & URB_ASYNC_UNLINK)) {
-				spin_lock_irqsave (&urb->lock, flags);
-				urb->complete = splice.complete;
-				urb->context = splice.context;
-				spin_unlock_irqrestore (&urb->lock, flags);
-			}
-			goto bye;
-		}
-	}
-
-    	/* block till giveback, if needed */
-	if (urb->transfer_flags & URB_ASYNC_UNLINK)
-		return -EINPROGRESS;
-
-	wait_for_completion (&splice.done);
-	return 0;
+	retval = unlink1 (hcd, urb);
+	if (retval == 0)
+		retval = -EINPROGRESS;
+	return retval;
 
 done:
 	spin_unlock (&hcd_data_lock);
 	spin_unlock_irqrestore (&urb->lock, flags);
-bye:
 	if (retval != -EIDRM && sys && sys->driver)
 		dev_dbg (sys, "hcd_unlink_urb %p fail %d\n", urb, retval);
 	return retval;
@@ -1367,13 +1311,10 @@
 
 rescan:
 	/* (re)block new requests, as best we can */
-	if (endpoint & USB_DIR_IN) {
-		usb_endpoint_halt (udev, epnum, 0);
+	if (endpoint & USB_DIR_IN)
 		udev->epmaxpacketin [epnum] = 0;
-	} else {
-		usb_endpoint_halt (udev, epnum, 1);
+	else
 		udev->epmaxpacketout [epnum] = 0;
-	}
 
 	/* then kill any current requests */
 	spin_lock (&hcd_data_lock);
@@ -1536,6 +1477,9 @@
 
 	/* pass ownership to the completion handler */
 	urb->complete (urb, regs);
+	atomic_dec (&urb->use_count);
+	if (unlikely (urb->reject))
+		wake_up (&usb_kill_urb_queue);
 	usb_put_urb (urb);
 }
 EXPORT_SYMBOL (usb_hcd_giveback_urb);
@@ -1579,13 +1523,13 @@
 	unsigned		i;
 
 	/* hc's root hub is removed later removed in hcd->stop() */
-	down (&hub->serialize);
 	usb_set_device_state(hub, USB_STATE_NOTATTACHED);
+	usb_lock_device (hub);
 	for (i = 0; i < hub->maxchild; i++) {
 		if (hub->children [i])
 			usb_disconnect (&hub->children [i]);
 	}
-	up (&hub->serialize);
+	usb_unlock_device (hub);
 }
 
 /**
diff -Nru a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
--- a/drivers/usb/core/hcd.h	2004-07-04 23:02:39 -07:00
+++ b/drivers/usb/core/hcd.h	2004-07-04 23:02:39 -07:00
@@ -142,7 +142,7 @@
 	int (*deallocate)(struct usb_device *);
 	int (*get_frame_number) (struct usb_device *usb_dev);
 	int (*submit_urb) (struct urb *urb, int mem_flags);
-	int (*unlink_urb) (struct urb *urb);
+	int (*unlink_urb) (struct urb *urb, int status);
 
 	/* allocate dma-consistent buffer for URB_DMA_NOMAPPING */
 	void *(*buffer_alloc)(struct usb_bus *bus, size_t size,
@@ -207,7 +207,7 @@
 
 extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs);
 extern void usb_bus_init (struct usb_bus *bus);
-extern void usb_rh_status_dequeue (struct usb_hcd *hcd, struct urb *urb);
+extern int usb_rh_status_dequeue (struct usb_hcd *hcd, struct urb *urb);
 
 #ifdef CONFIG_PCI
 struct pci_dev;
@@ -359,14 +359,13 @@
 
 extern struct list_head usb_bus_list;
 extern struct semaphore usb_bus_list_lock;
+extern wait_queue_head_t usb_kill_urb_queue;
 
 extern struct usb_bus *usb_bus_get (struct usb_bus *bus);
 extern void usb_bus_put (struct usb_bus *bus);
 
 extern int usb_find_interface_driver (struct usb_device *dev,
 	struct usb_interface *interface);
-
-#define usb_endpoint_halt(dev, ep, out) ((dev)->halted[out] |= (1 << (ep)))
 
 #define usb_endpoint_out(ep_dir)	(!((ep_dir) & USB_DIR_IN))
 
diff -Nru a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
--- a/drivers/usb/core/hub.c	2004-07-04 23:02:39 -07:00
+++ b/drivers/usb/core/hub.c	2004-07-04 23:02:39 -07:00
@@ -53,6 +53,8 @@
 module_param (blinkenlights, bool, S_IRUGO);
 MODULE_PARM_DESC (blinkenlights, "true to cycle leds on hubs");
 
+static int hub_port_disable(struct usb_device *hdev, int port);
+
 
 #ifdef	DEBUG
 static inline char *portspeed (int portstatus)
@@ -138,7 +140,7 @@
 static void led_work (void *__hub)
 {
 	struct usb_hub		*hub = __hub;
-	struct usb_device	*hdev = interface_to_usbdev (hub->intf);
+	struct usb_device	*hdev = hub->hdev;
 	unsigned		i;
 	unsigned		changed = 0;
 	int			cursor = -1;
@@ -234,18 +236,11 @@
 	int i;
 	unsigned long bits;
 
-	spin_lock(&hub_event_lock);
-	hub->urb_active = 0;
-	if (hub->urb_complete) {	/* disconnect or rmmod */
-		complete(hub->urb_complete);
-		goto done;
-	}
-
 	switch (urb->status) {
 	case -ENOENT:		/* synchronous unlink */
 	case -ECONNRESET:	/* async unlink */
 	case -ESHUTDOWN:	/* hardware going away */
-		goto done;
+		return;
 
 	default:		/* presumably an error */
 		/* Cause a hub reset after 10 consecutive errors */
@@ -268,20 +263,17 @@
 	hub->nerrors = 0;
 
 	/* Something happened, let khubd figure it out */
+	spin_lock(&hub_event_lock);
 	if (list_empty(&hub->event_list)) {
 		list_add_tail(&hub->event_list, &hub_event_list);
 		wake_up(&khubd_wait);
 	}
+	spin_unlock(&hub_event_lock);
 
 resubmit:
 	if ((status = usb_submit_urb (hub->urb, GFP_ATOMIC)) != 0
-			/* ENODEV means we raced disconnect() */
-			&& status != -ENODEV)
+			&& status != -ENODEV && status != -EPERM)
 		dev_err (&hub->intf->dev, "resubmit --> %d\n", status);
-	if (status == 0)
-		hub->urb_active = 1;
-done:
-	spin_unlock(&hub_event_lock);
 }
 
 /* USB 2.0 spec Section 11.24.2.3 */
@@ -308,7 +300,7 @@
 	while (!list_empty (&hub->tt.clear_list)) {
 		struct list_head	*temp;
 		struct usb_tt_clear	*clear;
-		struct usb_device	*hdev;
+		struct usb_device	*hdev = hub->hdev;
 		int			status;
 
 		temp = hub->tt.clear_list.next;
@@ -317,7 +309,6 @@
 
 		/* drop lock so HCD can concurrently report other TT errors */
 		spin_unlock_irqrestore (&hub->tt.lock, flags);
-		hdev = interface_to_usbdev (hub->intf);
 		status = hub_clear_tt_buffer (hdev, clear->devinfo, clear->tt);
 		spin_lock_irqsave (&hub->tt.lock, flags);
 
@@ -378,15 +369,14 @@
 
 static void hub_power_on(struct usb_hub *hub)
 {
-	struct usb_device *hdev;
 	int i;
 
 	/* 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");
-		hdev = interface_to_usbdev(hub->intf);
 		for (i = 0; i < hub->descriptor->bNbrPorts; i++)
-			set_port_feature(hdev, i + 1, USB_PORT_FEAT_POWER);
+			set_port_feature(hub->hdev, i + 1,
+					USB_PORT_FEAT_POWER);
 	}
 
 	/* Wait for power to be enabled */
@@ -396,10 +386,9 @@
 static int hub_hub_status(struct usb_hub *hub,
 		u16 *status, u16 *change)
 {
-	struct usb_device *hdev = interface_to_usbdev (hub->intf);
 	int ret;
 
-	ret = get_hub_status(hdev, &hub->status->hub);
+	ret = get_hub_status(hub->hdev, &hub->status->hub);
 	if (ret < 0)
 		dev_err (&hub->intf->dev,
 			"%s failed (err = %d)\n", __FUNCTION__, ret);
@@ -414,7 +403,7 @@
 static int hub_configure(struct usb_hub *hub,
 	struct usb_endpoint_descriptor *endpoint)
 {
-	struct usb_device *hdev = interface_to_usbdev (hub->intf);
+	struct usb_device *hdev = hub->hdev;
 	struct device *hub_dev = &hub->intf->dev;
 	u16 hubstatus, hubchange;
 	unsigned int pipe;
@@ -612,7 +601,6 @@
 		message = "couldn't submit status urb";
 		goto fail;
 	}
-	hub->urb_active = 1;
 
 	/* Wake up khubd */
 	wake_up(&khubd_wait);
@@ -635,26 +623,48 @@
 	return ret;
 }
 
+static void hub_remove_children_work(void *__hub)
+{
+	struct usb_hub		*hub = __hub;
+	struct usb_device	*hdev = hub->hdev;
+	int			i;
+
+	kfree(hub);
+
+	usb_lock_device(hdev);
+	for (i = 0; i < hdev->maxchild; ++i) {
+		if (hdev->children[i])
+			usb_disconnect(&hdev->children[i]);
+	}
+	usb_unlock_device(hdev);
+	usb_put_dev(hdev);
+}
+
 static unsigned highspeed_hubs;
 
 static void hub_disconnect(struct usb_interface *intf)
 {
 	struct usb_hub *hub = usb_get_intfdata (intf);
-	DECLARE_COMPLETION(urb_complete);
+	struct usb_device *hdev;
+	int i, n;
 
 	if (!hub)
 		return;
+	hdev = hub->hdev;
 
-	if (interface_to_usbdev(intf)->speed == USB_SPEED_HIGH)
+	if (hdev->speed == USB_SPEED_HIGH)
 		highspeed_hubs--;
 
 	usb_set_intfdata (intf, NULL);
-	spin_lock_irq(&hub_event_lock);
-	hub->urb_complete = &urb_complete;
 
-	/* Delete it and then reset it */
-	list_del_init(&hub->event_list);
+	if (hub->urb) {
+		usb_kill_urb(hub->urb);
+		usb_free_urb(hub->urb);
+		hub->urb = NULL;
+	}
 
+	spin_lock_irq(&hub_event_lock);
+	list_del_init(&hub->event_list);
 	spin_unlock_irq(&hub_event_lock);
 
 	/* assuming we used keventd, it must quiesce too */
@@ -663,14 +673,6 @@
 	if (hub->has_indicators || hub->tt.hub)
 		flush_scheduled_work ();
 
-	if (hub->urb) {
-		usb_unlink_urb(hub->urb);
-		if (hub->urb_active)
-			wait_for_completion(&urb_complete);
-		usb_free_urb(hub->urb);
-		hub->urb = NULL;
-	}
-
 	if (hub->descriptor) {
 		kfree(hub->descriptor);
 		hub->descriptor = NULL;
@@ -682,14 +684,32 @@
 	}
 
 	if (hub->buffer) {
-		usb_buffer_free(interface_to_usbdev(intf),
-				sizeof(*hub->buffer), hub->buffer,
+		usb_buffer_free(hdev, sizeof(*hub->buffer), hub->buffer,
 				hub->buffer_dma);
 		hub->buffer = NULL;
 	}
 
-	/* Free the memory */
-	kfree(hub);
+	/* If there are any children then this is unbind only, not a
+	 * physical disconnection.  The active ports must be disabled
+	 * and later on we must call usb_disconnect().  We can't call
+	 * it here because we already own the usb bus writelock.
+	 */
+	n = 0;
+	for (i = 0; i < hdev->maxchild; ++i) {
+		if (hdev->children[i]) {
+			++n;
+			hub_port_disable(hdev, i);
+		}
+	}
+
+	if (n == 0)
+		kfree(hub);
+	else {
+		/* Reuse hub->leds to disconnect the children */
+		INIT_WORK(&hub->leds, hub_remove_children_work, hub);
+		schedule_work(&hub->leds);
+		usb_get_dev(hdev);
+	}
 }
 
 static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
@@ -741,6 +761,7 @@
 
 	INIT_LIST_HEAD(&hub->event_list);
 	hub->intf = intf;
+	hub->hdev = hdev;
 	INIT_WORK(&hub->leds, led_work, hub);
 
 	usb_set_intfdata (intf, hub);
@@ -792,7 +813,7 @@
 
 static int hub_reset(struct usb_hub *hub)
 {
-	struct usb_device *hdev = interface_to_usbdev(hub->intf);
+	struct usb_device *hdev = hub->hdev;
 	int i;
 
 	/* Disconnect any attached devices */
@@ -803,7 +824,7 @@
 
 	/* Attempt to reset the hub */
 	if (hub->urb)
-		usb_unlink_urb(hub->urb);
+		usb_kill_urb(hub->urb);
 	else
 		return -1;
 
@@ -855,7 +876,7 @@
  * @udev: pointer to device whose state should be changed
  * @new_state: new state value to be stored
  *
- * udev->state is _not_ protected by the udev->serialize semaphore.  This
+ * udev->state is _not_ protected by the device lock.  This
  * is so that devices can be marked as disconnected as soon as possible,
  * without having to wait for the semaphore to be released.  Instead,
  * changes to the state must be protected by the device_state_lock spinlock.
@@ -946,7 +967,7 @@
 	/* lock the bus list on behalf of HCDs unregistering their root hubs */
 	if (!udev->parent)
 		down(&usb_bus_list_lock);
-	down(&udev->serialize);
+	usb_lock_device(udev);
 
 	dev_info (&udev->dev, "USB disconnect, address %d\n", udev->devnum);
 
@@ -975,7 +996,7 @@
 	*pdev = NULL;
 	spin_unlock_irq(&device_state_lock);
 
-	up(&udev->serialize);
+	usb_unlock_device(udev);
 	if (!udev->parent)
 		up(&usb_bus_list_lock);
 
@@ -1467,8 +1488,6 @@
 				!= udev->descriptor.bMaxPacketSize0)) {
 		usb_disable_endpoint(udev, 0 + USB_DIR_IN);
 		usb_disable_endpoint(udev, 0 + USB_DIR_OUT);
-		usb_endpoint_running(udev, 0, 1);
-		usb_endpoint_running(udev, 0, 0);
 		udev->epmaxpacketin [0] = udev->descriptor.bMaxPacketSize0;
 		udev->epmaxpacketout[0] = udev->descriptor.bMaxPacketSize0;
 	}
@@ -1514,8 +1533,9 @@
 }
 
 static unsigned
-hub_power_remaining (struct usb_hub *hub, struct usb_device *hdev)
+hub_power_remaining (struct usb_hub *hub)
 {
+	struct usb_device *hdev = hub->hdev;
 	int remaining;
 	unsigned i;
 
@@ -1556,7 +1576,7 @@
 static void hub_port_connect_change(struct usb_hub *hub, int port,
 					u16 portstatus, u16 portchange)
 {
-	struct usb_device *hdev = interface_to_usbdev(hub->intf);
+	struct usb_device *hdev = hub->hdev;
 	struct device *hub_dev = &hub->intf->dev;
 	int status, i;
  
@@ -1673,7 +1693,7 @@
 		 * udev becomes globally accessible, although presumably
 		 * no one will look at it until hdev is unlocked.
 		 */
-		down (&udev->serialize);
+		usb_lock_device (udev);
 		status = 0;
 
 		/* We mustn't add new devices if the parent hub has
@@ -1697,11 +1717,11 @@
 			}
 		}
 
-		up (&udev->serialize);
+		usb_unlock_device (udev);
 		if (status)
 			goto loop;
 
-		status = hub_power_remaining(hub, hdev);
+		status = hub_power_remaining(hub);
 		if (status)
 			dev_dbg(hub_dev,
 				"%dmA power budget left\n",
@@ -1755,7 +1775,7 @@
 		list_del_init(tmp);
 
 		hub = list_entry(tmp, struct usb_hub, event_list);
-		hdev = interface_to_usbdev(hub->intf);
+		hdev = hub->hdev;
 		hub_dev = &hub->intf->dev;
 
 		usb_get_dev(hdev);
@@ -1763,7 +1783,7 @@
 
 		/* Lock the device, then check to see if we were
 		 * disconnected while waiting for the lock to succeed. */
-		down(&hdev->serialize);
+		usb_lock_device(hdev);
 		if (hdev->state != USB_STATE_CONFIGURED ||
 				!hdev->actconfig ||
 				hub != usb_get_intfdata(
@@ -1879,7 +1899,7 @@
 		}
 
 loop:
-		up(&hdev->serialize);
+		usb_unlock_device(hdev);
 		usb_put_dev(hdev);
 
         } /* end while (1) */
@@ -2030,8 +2050,10 @@
  *
  * The caller must own the device lock.  For example, it's safe to use
  * this from a driver probe() routine after downloading new firmware.
+ * For calls that might not occur during probe(), drivers should lock
+ * the device using usb_lock_device_for_reset().
  */
-int __usb_reset_device(struct usb_device *udev)
+int usb_reset_device(struct usb_device *udev)
 {
 	struct usb_device *parent = udev->parent;
 	struct usb_device_descriptor descriptor = udev->descriptor;
@@ -2067,6 +2089,11 @@
 		return -ENOENT;
 	}
 
+	/* ep0 maxpacket size may change; let the HCD know about it.
+	 * Other endpoints will be handled by re-enumeration. */
+	usb_disable_endpoint(udev, 0);
+	usb_disable_endpoint(udev, 0 + USB_DIR_IN);
+
 	ret = hub_port_init(parent, udev, port);
 	if (ret < 0)
 		goto re_enumerate;
@@ -2098,7 +2125,7 @@
 		struct usb_interface *intf = udev->actconfig->interface[i];
 		struct usb_interface_descriptor *desc;
 
-		/* set_interface resets host side toggle and halt status even
+		/* set_interface resets host side toggle even
 		 * for altsetting zero.  the interface may have no driver.
 		 */
 		desc = &intf->cur_altsetting->desc;
@@ -2130,16 +2157,4 @@
 	spin_unlock_irq(&hub_event_lock);
 
 	return -ENODEV;
-}
-EXPORT_SYMBOL(__usb_reset_device);
-
-int usb_reset_device(struct usb_device *udev)
-{
-	int r;
-	
-	down(&udev->serialize);
-	r = __usb_reset_device(udev);
-	up(&udev->serialize);
-
-	return r;
 }
diff -Nru a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h
--- a/drivers/usb/core/hub.h	2004-07-04 23:02:39 -07:00
+++ b/drivers/usb/core/hub.h	2004-07-04 23:02:39 -07:00
@@ -187,9 +187,8 @@
 
 struct usb_hub {
 	struct usb_interface	*intf;		/* the "real" device */
+	struct usb_device	*hdev;
 	struct urb		*urb;		/* for interrupt polling pipe */
-	struct completion	*urb_complete;	/* wait for urb to end */
-	unsigned int		urb_active:1;
 
 	/* buffer for urb ... 1 bit each for hub and children, rounded up */
 	char			(*buffer)[(USB_MAXCHILDREN + 1 + 7) / 8];
diff -Nru a/drivers/usb/core/message.c b/drivers/usb/core/message.c
--- a/drivers/usb/core/message.c	2004-07-04 23:02:39 -07:00
+++ b/drivers/usb/core/message.c	2004-07-04 23:02:39 -07:00
@@ -605,12 +605,128 @@
  * Returns the number of bytes received on success, or else the status code
  * returned by the underlying usb_control_msg() call.
  */
-int usb_get_string(struct usb_device *dev, unsigned short langid, unsigned char index, void *buf, int size)
+int usb_get_string(struct usb_device *dev, unsigned short langid,
+		unsigned char index, void *buf, int size)
 {
-	return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-		USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
-		(USB_DT_STRING << 8) + index, langid, buf, size,
-		HZ * USB_CTRL_GET_TIMEOUT);
+	int i;
+	int result;
+
+	for (i = 0; i < 3; ++i) {
+		/* retry on length 0 or stall; some devices are flakey */
+		result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+			USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
+			(USB_DT_STRING << 8) + index, langid, buf, size,
+			HZ * USB_CTRL_GET_TIMEOUT);
+		if (!(result == 0 || result == -EPIPE))
+			break;
+	}
+	return result;
+}
+
+static int usb_string_sub(struct usb_device *dev, unsigned int langid,
+		unsigned int index, unsigned char *buf)
+{
+	int rc;
+
+	/* Try to read the string descriptor by asking for the maximum
+	 * possible number of bytes */
+	rc = usb_get_string(dev, langid, index, buf, 255);
+
+	/* If that failed try to read the descriptor length, then
+	 * ask for just that many bytes */
+	if (rc < 0) {
+		rc = usb_get_string(dev, langid, index, buf, 2);
+		if (rc == 2)
+			rc = usb_get_string(dev, langid, index, buf, buf[0]);
+	}
+
+	if (rc >= 0) {
+		/* There might be extra junk at the end of the descriptor */
+		if (buf[0] < rc)
+			rc = buf[0];
+		if (rc < 2)
+			rc = -EINVAL;
+	}
+	return rc;
+}
+
+/**
+ * usb_string - returns ISO 8859-1 version of a string descriptor
+ * @dev: the device whose string descriptor is being retrieved
+ * @index: the number of the descriptor
+ * @buf: where to put the string
+ * @size: how big is "buf"?
+ * Context: !in_interrupt ()
+ * 
+ * This converts the UTF-16LE encoded strings returned by devices, from
+ * usb_get_string_descriptor(), to null-terminated ISO-8859-1 encoded ones
+ * that are more usable in most kernel contexts.  Note that all characters
+ * in the chosen descriptor that can't be encoded using ISO-8859-1
+ * are converted to the question mark ("?") character, and this function
+ * chooses strings in the first language supported by the device.
+ *
+ * The ASCII (or, redundantly, "US-ASCII") character set is the seven-bit
+ * subset of ISO 8859-1. ISO-8859-1 is the eight-bit subset of Unicode,
+ * and is appropriate for use many uses of English and several other
+ * Western European languages.  (But it doesn't include the "Euro" symbol.)
+ *
+ * This call is synchronous, and may not be used in an interrupt context.
+ *
+ * Returns length of the string (>= 0) or usb_control_msg status (< 0).
+ */
+int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
+{
+	unsigned char *tbuf;
+	int err;
+	unsigned int u, idx;
+
+	if (size <= 0 || !buf || !index)
+		return -EINVAL;
+	buf[0] = 0;
+	tbuf = kmalloc(256, GFP_KERNEL);
+	if (!tbuf)
+		return -ENOMEM;
+
+	/* get langid for strings if it's not yet known */
+	if (!dev->have_langid) {
+		err = usb_string_sub(dev, 0, 0, tbuf);
+		if (err < 0) {
+			dev_err (&dev->dev,
+				"string descriptor 0 read error: %d\n",
+				err);
+			goto errout;
+		} else if (err < 4) {
+			dev_err (&dev->dev, "string descriptor 0 too short\n");
+			err = -EINVAL;
+			goto errout;
+		} else {
+			dev->have_langid = -1;
+			dev->string_langid = tbuf[2] | (tbuf[3]<< 8);
+				/* always use the first langid listed */
+			dev_dbg (&dev->dev, "default language 0x%04x\n",
+				dev->string_langid);
+		}
+	}
+	
+	err = usb_string_sub(dev, dev->string_langid, index, tbuf);
+	if (err < 0)
+		goto errout;
+
+	size--;		/* leave room for trailing NULL char in output buffer */
+	for (idx = 0, u = 2; u < err; u += 2) {
+		if (idx >= size)
+			break;
+		if (tbuf[u+1])			/* high byte */
+			buf[idx++] = '?';  /* non ISO-8859-1 character */
+		else
+			buf[idx++] = tbuf[u];
+	}
+	buf[idx] = 0;
+	err = idx;
+
+ errout:
+	kfree(tbuf);
+	return err;
 }
 
 /**
@@ -738,9 +854,8 @@
 	 * the copy in usb-storage, for as long as we need two copies.
 	 */
 
-	/* toggle was reset by the clear, then ep was reactivated */
+	/* toggle was reset by the clear */
 	usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0);
-	usb_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
 
 	return 0;
 }
@@ -754,9 +869,8 @@
  * Deallocates hcd/hardware state for this endpoint ... and nukes all
  * pending urbs.
  *
- * If the HCD hasn't registered a disable() function, this marks the
- * endpoint as halted and sets its maxpacket size to 0 to prevent
- * further submissions.
+ * If the HCD hasn't registered a disable() function, this sets the
+ * endpoint's maxpacket size to 0 to prevent further submissions.
  */
 void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr)
 {
@@ -765,13 +879,10 @@
 	else {
 		unsigned int epnum = epaddr & USB_ENDPOINT_NUMBER_MASK;
 
-		if (usb_endpoint_out(epaddr)) {
-			usb_endpoint_halt(dev, epnum, 1);
+		if (usb_endpoint_out(epaddr))
 			dev->epmaxpacketout[epnum] = 0;
-		} else {
-			usb_endpoint_halt(dev, epnum, 0);
+		else
 			dev->epmaxpacketin[epnum] = 0;
-		}
 	}
 }
 
@@ -814,7 +925,6 @@
 		usb_disable_endpoint(dev, i + USB_DIR_IN);
 	}
 	dev->toggle[0] = dev->toggle[1] = 0;
-	dev->halted[0] = dev->halted[1] = 0;
 
 	/* getting rid of interfaces will disconnect
 	 * any drivers bound to them (a key side effect)
@@ -850,9 +960,8 @@
  * @dev: the device whose interface is being enabled
  * @epd: pointer to the endpoint descriptor
  *
- * Marks the endpoint as running, resets its toggle, and stores
- * its maxpacket value.  For control endpoints, both the input
- * and output sides are handled.
+ * Resets the endpoint toggle and stores its maxpacket value.
+ * For control endpoints, both the input and output sides are handled.
  */
 void usb_enable_endpoint(struct usb_device *dev,
 		struct usb_endpoint_descriptor *epd)
@@ -864,12 +973,10 @@
 				USB_ENDPOINT_XFER_CONTROL);
 
 	if (usb_endpoint_out(epaddr) || is_control) {
-		usb_endpoint_running(dev, epnum, 1);
 		usb_settoggle(dev, epnum, 1, 0);
 		dev->epmaxpacketout[epnum] = maxsize;
 	}
 	if (!usb_endpoint_out(epaddr) || is_control) {
-		usb_endpoint_running(dev, epnum, 0);
 		usb_settoggle(dev, epnum, 0, 0);
 		dev->epmaxpacketin[epnum] = maxsize;
 	}
@@ -932,6 +1039,9 @@
 	int ret;
 	int manual = 0;
 
+	if (dev->state == USB_STATE_SUSPENDED)
+		return -EHOSTUNREACH;
+
 	iface = usb_ifnum_to_if(dev, interface);
 	if (!iface) {
 		dev_dbg(&dev->dev, "selecting invalid interface %d\n",
@@ -1022,6 +1132,8 @@
  * use usb_set_interface() on the interfaces it claims.  Resetting the whole
  * configuration would affect other drivers' interfaces.
  *
+ * The caller must have locked the device.
+ *
  * Returns zero on success, else a negative error code.
  */
 int usb_reset_configuration(struct usb_device *dev)
@@ -1029,8 +1141,11 @@
 	int			i, retval;
 	struct usb_host_config	*config;
 
-	/* caller must own dev->serialize (config won't change)
-	 * and the usb bus readlock (so driver bindings are stable);
+	if (dev->state == USB_STATE_SUSPENDED)
+		return -EHOSTUNREACH;
+
+	/* caller must have locked the device and must own
+	 * the usb bus readlock (so driver bindings are stable);
 	 * so calls during probe() are fine
 	 */
 
@@ -1050,7 +1165,6 @@
 	}
 
 	dev->toggle[0] = dev->toggle[1] = 0;
-	dev->halted[0] = dev->halted[1] = 0;
 
 	/* re-init hc/hcd interface/endpoint state */
 	for (i = 0; i < config->desc.bNumInterfaces; i++) {
@@ -1087,7 +1201,7 @@
  * usb_set_configuration - Makes a particular device setting be current
  * @dev: the device whose configuration is being updated
  * @configuration: the configuration being chosen.
- * Context: !in_interrupt(), caller holds dev->serialize
+ * Context: !in_interrupt(), caller has locked the device
  *
  * This is used to enable non-default device modes.  Not all devices
  * use this kind of configurability; many devices only have one
@@ -1108,8 +1222,8 @@
  * usb_set_interface().
  *
  * This call is synchronous. The calling context must be able to sleep,
- * and must not hold the driver model lock for USB; usb device driver
- * probe() methods may not use this routine.
+ * must have locked the device, and must not hold the driver model lock
+ * for USB; usb device driver probe() methods cannot use this routine.
  *
  * Returns zero on success, or else the status code returned by the
  * underlying call that failed.  On succesful completion, each interface
@@ -1124,8 +1238,6 @@
 	struct usb_interface **new_interfaces = NULL;
 	int n, nintf;
 
-	/* dev->serialize guards all config changes */
-
 	for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
 		if (dev->config[i].desc.bConfigurationValue == configuration) {
 			cp = &dev->config[i];
@@ -1142,6 +1254,9 @@
 	if (cp && configuration == 0)
 		dev_warn(&dev->dev, "config 0 descriptor??\n");
 
+	if (dev->state == USB_STATE_SUSPENDED)
+		return -EHOSTUNREACH;
+
 	/* Allocate memory for new interfaces before doing anything else,
 	 * so that if we run out then nothing will have changed. */
 	n = nintf = 0;
@@ -1255,102 +1370,6 @@
 	}
 
 	return ret;
-}
-
-/**
- * usb_string - returns ISO 8859-1 version of a string descriptor
- * @dev: the device whose string descriptor is being retrieved
- * @index: the number of the descriptor
- * @buf: where to put the string
- * @size: how big is "buf"?
- * Context: !in_interrupt ()
- * 
- * This converts the UTF-16LE encoded strings returned by devices, from
- * usb_get_string_descriptor(), to null-terminated ISO-8859-1 encoded ones
- * that are more usable in most kernel contexts.  Note that all characters
- * in the chosen descriptor that can't be encoded using ISO-8859-1
- * are converted to the question mark ("?") character, and this function
- * chooses strings in the first language supported by the device.
- *
- * The ASCII (or, redundantly, "US-ASCII") character set is the seven-bit
- * subset of ISO 8859-1. ISO-8859-1 is the eight-bit subset of Unicode,
- * and is appropriate for use many uses of English and several other
- * Western European languages.  (But it doesn't include the "Euro" symbol.)
- *
- * This call is synchronous, and may not be used in an interrupt context.
- *
- * Returns length of the string (>= 0) or usb_control_msg status (< 0).
- */
-int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
-{
-	unsigned char *tbuf;
-	int err, len;
-	unsigned int u, idx;
-
-	if (size <= 0 || !buf || !index)
-		return -EINVAL;
-	buf[0] = 0;
-	tbuf = kmalloc(256, GFP_KERNEL);
-	if (!tbuf)
-		return -ENOMEM;
-
-	/* get langid for strings if it's not yet known */
-	if (!dev->have_langid) {
-		err = usb_get_descriptor(dev, USB_DT_STRING, 0, tbuf, 4);
-		if (err < 0) {
-			dev_err (&dev->dev,
-				"string descriptor 0 read error: %d\n",
-				err);
-			goto errout;
-		} else if (err < 4 || tbuf[0] < 4) {
-			dev_err (&dev->dev, "string descriptor 0 too short\n");
-			err = -EINVAL;
-			goto errout;
-		} else {
-			dev->have_langid = -1;
-			dev->string_langid = tbuf[2] | (tbuf[3]<< 8);
-				/* always use the first langid listed */
-			dev_dbg (&dev->dev, "default language 0x%04x\n",
-				dev->string_langid);
-		}
-	}
-
-	/*
-	 * ask for the length of the string 
-	 */
-
-	err = usb_get_string(dev, dev->string_langid, index, tbuf, 2);
-	if (err == -EPIPE || err == 0) {
-		dev_dbg(&dev->dev, "RETRY string %d read/%d\n", index, 2);
-		err = usb_get_string(dev, dev->string_langid, index, tbuf, 2);
-	}
-	if(err<2)
-		goto errout;
-	len=tbuf[0];	
-	
-	err = usb_get_string(dev, dev->string_langid, index, tbuf, len);
-	if (err == -EPIPE || err == 0) {
-		dev_dbg(&dev->dev, "RETRY string %d read/%d\n", index, len);
-		err = usb_get_string(dev, dev->string_langid, index, tbuf, len);
-	}
-	if (err < 0)
-		goto errout;
-
-	size--;		/* leave room for trailing NULL char in output buffer */
-	for (idx = 0, u = 2; u < err; u += 2) {
-		if (idx >= size)
-			break;
-		if (tbuf[u+1])			/* high byte */
-			buf[idx++] = '?';  /* non ISO-8859-1 character */
-		else
-			buf[idx++] = tbuf[u];
-	}
-	buf[idx] = 0;
-	err = idx;
-
- errout:
-	kfree(tbuf);
-	return err;
 }
 
 // synchronous request completion model
diff -Nru a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
--- a/drivers/usb/core/sysfs.c	2004-07-04 23:02:39 -07:00
+++ b/drivers/usb/core/sysfs.c	2004-07-04 23:02:39 -07:00
@@ -55,9 +55,9 @@
 
 	if (sscanf (buf, "%u", &config) != 1 || config > 255)
 		return -EINVAL;
-	down(&udev->serialize);
+	usb_lock_device(udev);
 	value = usb_set_configuration (udev, config);
-	up(&udev->serialize);
+	usb_unlock_device(udev);
 	return (value < 0) ? value : count;
 }
 
diff -Nru a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
--- a/drivers/usb/core/urb.c	2004-07-04 23:02:39 -07:00
+++ b/drivers/usb/core/urb.c	2004-07-04 23:02:39 -07:00
@@ -256,13 +256,6 @@
 	if (!usb_pipecontrol (pipe) && dev->state < USB_STATE_CONFIGURED)
 		return -ENODEV;
 
-	/* (actually HCDs may need to duplicate this, endpoint might yet
-	 * stall due to queued bulk/intr transactions that complete after
-	 * we check)
-	 */
-	if (usb_endpoint_halted (dev, usb_pipeendpoint (pipe), is_out))
-		return -EPIPE;
-
 	/* FIXME there should be a sharable lock protecting us against
 	 * config/altsetting changes and disconnects, kicking in here.
 	 * (here == before maxpacket, and eventually endpoint type,
@@ -407,26 +400,25 @@
  * canceled (rather than any other code) and will quickly be removed
  * from host controller data structures.
  *
- * When the URB_ASYNC_UNLINK transfer flag for the URB is clear, this
- * request is synchronous.  Success is indicated by returning zero,
- * at which time the urb will have been unlinked and its completion
- * handler will have been called with urb->status == -ENOENT.  Failure is
- * indicated by any other return value.
- *
- * The synchronous cancelation mode may not be used
- * when unlinking an urb from an interrupt context, such as a bottom
- * half or a completion handler; or when holding a spinlock; or in
- * other cases when the caller can't schedule().
+ * In the past, clearing the URB_ASYNC_UNLINK transfer flag for the
+ * URB indicated that the request was synchronous.  This usage is now
+ * deprecated; if the flag is clear the call will be forwarded to
+ * usb_kill_urb() and the return value will be 0.  In the future, drivers
+ * should call usb_kill_urb() directly for synchronous unlinking.
  *
  * When the URB_ASYNC_UNLINK transfer flag for the URB is set, this
  * request is asynchronous.  Success is indicated by returning -EINPROGRESS,
- * at which time the urb will normally not have been unlinked.
- * The completion function will see urb->status == -ECONNRESET.  Failure
- * is indicated by any other return value.
+ * at which time the URB will normally have been unlinked but not yet
+ * given back to the device driver.  When it is called, the completion
+ * function will see urb->status == -ECONNRESET.  Failure is indicated
+ * by any other return value.  Unlinking will fail when the URB is not
+ * currently "linked" (i.e., it was never submitted, or it was unlinked
+ * before, or the hardware is already finished with it), even if the
+ * completion handler has not yet run.
  *
  * Unlinking and Endpoint Queues:
  *
- * Host Controller Driver (HCDs) place all the URBs for a particular
+ * Host Controller Drivers (HCDs) place all the URBs for a particular
  * endpoint in a queue.  Normally the queue advances as the controller
  * hardware processes each request.  But when an URB terminates with any
  * fault (such as an error, or being unlinked) its queue stops, at least
@@ -449,16 +441,54 @@
  * An unlinked URB may leave a gap in the stream of packets.  It is undefined
  * whether such gaps can be filled in.
  *
- * When control URBs terminates with an error, it is likely that the
+ * When a control URB terminates with an error, it is likely that the
  * status stage of the transfer will not take place, even if it is merely
  * a soft error resulting from a short-packet with URB_SHORT_NOT_OK set.
  */
 int usb_unlink_urb(struct urb *urb)
 {
-	if (urb && urb->dev && urb->dev->bus && urb->dev->bus->op)
-		return urb->dev->bus->op->unlink_urb(urb);
-	else
+	if (!(urb->transfer_flags & URB_ASYNC_UNLINK)) {
+		usb_kill_urb(urb);
+		return 0;
+	}
+	if (!(urb->dev && urb->dev->bus && urb->dev->bus->op))
 		return -ENODEV;
+	return urb->dev->bus->op->unlink_urb(urb, -ECONNRESET);
+}
+
+/**
+ * usb_kill_urb - cancel a transfer request and wait for it to finish
+ * @urb: pointer to URB describing a previously submitted request
+ *
+ * This routine cancels an in-progress request.  It is guaranteed that
+ * upon return all completion handlers will have finished and the URB
+ * will be totally idle and available for reuse.  These features make
+ * this an ideal way to stop I/O in a disconnect() callback or close()
+ * function.  If the request has not already finished or been unlinked
+ * the completion handler will see urb->status == -ENOENT.
+ *
+ * While the routine is running, attempts to resubmit the URB will fail
+ * with error -EPERM.  Thus even if the URB's completion handler always
+ * tries to resubmit, it will not succeed and the URB will become idle.
+ *
+ * This routine may not be used in an interrupt context (such as a bottom
+ * half or a completion handler), or when holding a spinlock, or in other
+ * situations where the caller can't schedule().
+ */
+void usb_kill_urb(struct urb *urb)
+{
+	if (!(urb->dev && urb->dev->bus && urb->dev->bus->op))
+		return;
+	spin_lock_irq(&urb->lock);
+	++urb->reject;
+	spin_unlock_irq(&urb->lock);
+
+	urb->dev->bus->op->unlink_urb(urb, -ENOENT);
+	wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0);
+
+	spin_lock_irq(&urb->lock);
+	--urb->reject;
+	spin_unlock_irq(&urb->lock);
 }
 
 EXPORT_SYMBOL(usb_init_urb);
@@ -467,4 +497,5 @@
 EXPORT_SYMBOL(usb_get_urb);
 EXPORT_SYMBOL(usb_submit_urb);
 EXPORT_SYMBOL(usb_unlink_urb);
+EXPORT_SYMBOL(usb_kill_urb);
 
diff -Nru a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
--- a/drivers/usb/core/usb.c	2004-07-04 23:02:39 -07:00
+++ b/drivers/usb/core/usb.c	2004-07-04 23:02:39 -07:00
@@ -39,6 +39,7 @@
 #include <linux/spinlock.h>
 #include <linux/errno.h>
 #include <linux/smp_lock.h>
+#include <linux/rwsem.h>
 #include <linux/usb.h>
 
 #include <asm/io.h>
@@ -62,6 +63,8 @@
 int nousb;		/* Disable USB when built into kernel image */
 			/* Not honored on modular build */
 
+static DECLARE_RWSEM(usb_all_devices_rwsem);
+
 
 static int generic_probe (struct device *dev)
 {
@@ -93,11 +96,16 @@
 
 	if (!driver->probe)
 		return error;
+	if (interface_to_usbdev(intf)->state == USB_STATE_SUSPENDED)
+		return -EHOSTUNREACH;
 
 	id = usb_match_id (intf, driver->id_table);
 	if (id) {
 		dev_dbg (dev, "%s - got id\n", __FUNCTION__);
+		intf->condition = USB_INTERFACE_BINDING;
 		error = driver->probe (intf, id);
+		intf->condition = error ? USB_INTERFACE_UNBOUND :
+				USB_INTERFACE_BOUND;
 	}
 
 	return error;
@@ -109,6 +117,8 @@
 	struct usb_interface *intf = to_usb_interface(dev);
 	struct usb_driver *driver = to_usb_driver(intf->dev.driver);
 
+	intf->condition = USB_INTERFACE_UNBINDING;
+
 	/* release all urbs for this interface */
 	usb_disable_interface(interface_to_usbdev(intf), intf);
 
@@ -120,6 +130,7 @@
 			intf->altsetting[0].desc.bInterfaceNumber,
 			0);
 	usb_set_intfdata(intf, NULL);
+	intf->condition = USB_INTERFACE_UNBOUND;
 
 	return 0;
 }
@@ -149,7 +160,9 @@
 	new_driver->driver.probe = usb_probe_interface;
 	new_driver->driver.remove = usb_unbind_interface;
 
+	usb_lock_all_devices();
 	retval = driver_register(&new_driver->driver);
+	usb_unlock_all_devices();
 
 	if (!retval) {
 		pr_info("%s: registered new driver %s\n",
@@ -178,7 +191,9 @@
 {
 	pr_info("%s: deregistering driver %s\n", usbcore_name, driver->name);
 
+	usb_lock_all_devices();
 	driver_unregister (&driver->driver);
+	usb_unlock_all_devices();
 
 	usbfs_update_special();
 }
@@ -200,7 +215,7 @@
  * alternate settings available for this interfaces.
  *
  * Don't call this function unless you are bound to one of the interfaces
- * on this device or you own the dev->serialize semaphore!
+ * on this device or you have locked the device!
  */
 struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum)
 {
@@ -233,7 +248,7 @@
  * drivers avoid such mistakes.
  *
  * Don't call this function unless you are bound to the intf interface
- * or you own the device's ->serialize semaphore!
+ * or you have locked the device!
  */
 struct usb_host_interface *usb_altnum_to_altsetting(struct usb_interface *intf,
 		unsigned int altnum)
@@ -301,9 +316,9 @@
  * way to bind to an interface is to return the private data from
  * the driver's probe() method.
  *
- * Callers must own the driver model's usb bus writelock.  So driver
- * probe() entries don't need extra locking, but other call contexts
- * may need to explicitly claim that lock.
+ * Callers must lock the device and own the driver model's usb bus writelock.
+ * So driver probe() entries don't need extra locking, but other call contexts
+ * may need to explicitly claim those locks.
  */
 int usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void* priv)
 {
@@ -314,6 +329,7 @@
 
 	dev->driver = &driver->driver;
 	usb_set_intfdata(iface, priv);
+	iface->condition = USB_INTERFACE_BOUND;
 
 	/* if interface was already added, bind now; else let
 	 * the future device_add() bind it, bypassing probe()
@@ -334,8 +350,8 @@
  * also causes the driver disconnect() method to be called.
  *
  * This call is synchronous, and may not be used in an interrupt context.
- * Callers must own the usb_device serialize semaphore and the driver model's
- * usb bus writelock.  So driver disconnect() entries don't need extra locking,
+ * Callers must lock the device and own the driver model's usb bus writelock.
+ * So driver disconnect() entries don't need extra locking,
  * but other call contexts may need to explicitly claim those locks.
  */
 void usb_driver_release_interface(struct usb_driver *driver,
@@ -353,6 +369,7 @@
 
 	dev->driver = NULL;
 	usb_set_intfdata(iface, NULL);
+	iface->condition = USB_INTERFACE_UNBOUND;
 }
 
 /**
@@ -828,6 +845,116 @@
 		put_device(&intf->dev);
 }
 
+/**
+ * usb_lock_device - acquire the lock for a usb device structure
+ * @udev: device that's being locked
+ *
+ * Use this routine rather than manipulating udev->serialize directly.
+ * This is necessary for proper interaction with usb_lock_all_devices().
+ */
+void usb_lock_device(struct usb_device *udev)
+{
+	down_read(&usb_all_devices_rwsem);
+	down(&udev->serialize);
+}
+
+/**
+ * usb_trylock_device - attempt to acquire the lock for a usb device structure
+ * @udev: device that's being locked
+ *
+ * Use this routine rather than manipulating udev->serialize directly.
+ * This is necessary for proper interaction with usb_lock_all_devices().
+ *
+ * Returns 1 if successful, 0 if contention.
+ */
+int usb_trylock_device(struct usb_device *udev)
+{
+	if (!down_read_trylock(&usb_all_devices_rwsem))
+		return 0;
+	if (!down_trylock(&udev->serialize)) {
+		up_read(&usb_all_devices_rwsem);
+		return 0;
+	}
+	return 1;
+}
+
+/**
+ * usb_lock_device_for_reset - cautiously acquire the lock for a
+ *	usb device structure
+ * @udev: device that's being locked
+ * @iface: interface bound to the driver making the request (optional)
+ *
+ * Attempts to acquire the device lock, but fails if the device is
+ * NOTATTACHED or SUSPENDED, or if iface is specified and the interface
+ * is neither BINDING nor BOUND.  Rather than sleeping to wait for the
+ * lock, the routine polls repeatedly.  This is to prevent deadlock with
+ * disconnect; in some drivers (such as usb-storage) the disconnect()
+ * callback will block waiting for a device reset to complete.
+ *
+ * Returns a negative error code for failure, otherwise 1 or 0 to indicate
+ * that the device will or will not have to be unlocked.  (0 can be
+ * returned when an interface is given and is BINDING, because in that
+ * case the driver already owns the device lock.)
+ */
+int usb_lock_device_for_reset(struct usb_device *udev,
+		struct usb_interface *iface)
+{
+	if (udev->state == USB_STATE_NOTATTACHED)
+		return -ENODEV;
+	if (iface) {
+		switch (iface->condition) {
+		  case USB_INTERFACE_BINDING:
+			return 0;
+		  case USB_INTERFACE_BOUND:
+			break;
+		  default:
+			return -EINTR;
+		}
+	}
+
+	while (!usb_trylock_device(udev)) {
+		msleep(15);
+		if (udev->state == USB_STATE_NOTATTACHED)
+			return -ENODEV;
+		if (iface && iface->condition != USB_INTERFACE_BOUND)
+			return -EINTR;
+	}
+	return 1;
+}
+
+/**
+ * usb_unlock_device - release the lock for a usb device structure
+ * @udev: device that's being unlocked
+ *
+ * Use this routine rather than manipulating udev->serialize directly.
+ * This is necessary for proper interaction with usb_lock_all_devices().
+ */
+void usb_unlock_device(struct usb_device *udev)
+{
+	up(&udev->serialize);
+	up_read(&usb_all_devices_rwsem);
+}
+
+/**
+ * usb_lock_all_devices - acquire the lock for all usb device structures
+ *
+ * This is necessary when registering a new driver or probing a bus,
+ * since the driver-model core may try to use any usb_device.
+ */
+void usb_lock_all_devices(void)
+{
+	down_write(&usb_all_devices_rwsem);
+}
+
+/**
+ * usb_unlock_all_devices - release the lock for all usb device structures
+ */
+void usb_unlock_all_devices(void)
+{
+	up_write(&usb_all_devices_rwsem);
+}
+
+
 static struct usb_device *match_device(struct usb_device *dev,
 				       u16 vendor_id, u16 product_id)
 {
@@ -849,8 +976,10 @@
 	/* look through all of the children of this device */
 	for (child = 0; child < dev->maxchild; ++child) {
 		if (dev->children[child]) {
+			usb_lock_device(dev->children[child]);
 			ret_dev = match_device(dev->children[child],
 					       vendor_id, product_id);
+			usb_unlock_device(dev->children[child]);
 			if (ret_dev)
 				goto exit;
 		}
@@ -885,7 +1014,9 @@
 		bus = container_of(buslist, struct usb_bus, bus_list);
 		if (!bus->root_hub)
 			continue;
+		usb_lock_device(bus->root_hub);
 		dev = match_device(bus->root_hub, vendor_id, product_id);
+		usb_unlock_device(bus->root_hub);
 		if (dev)
 			goto exit;
 	}
@@ -1362,6 +1493,11 @@
 EXPORT_SYMBOL(usb_put_dev);
 EXPORT_SYMBOL(usb_get_dev);
 EXPORT_SYMBOL(usb_hub_tt_clear_buffer);
+
+EXPORT_SYMBOL(usb_lock_device);
+EXPORT_SYMBOL(usb_trylock_device);
+EXPORT_SYMBOL(usb_lock_device_for_reset);
+EXPORT_SYMBOL(usb_unlock_device);
 
 EXPORT_SYMBOL(usb_driver_claim_interface);
 EXPORT_SYMBOL(usb_driver_release_interface);
diff -Nru a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
--- a/drivers/usb/core/usb.h	2004-07-04 23:02:39 -07:00
+++ b/drivers/usb/core/usb.h	2004-07-04 23:02:39 -07:00
@@ -24,5 +24,8 @@
 extern void usb_set_device_state(struct usb_device *udev,
 		enum usb_device_state new_state);
 
+extern void usb_lock_all_devices(void);
+extern void usb_unlock_all_devices(void);
+
 /* for labeling diagnostics */
 extern const char *usbcore_name;
diff -Nru a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
--- a/drivers/usb/host/ehci-hub.c	2004-07-04 23:02:39 -07:00
+++ b/drivers/usb/host/ehci-hub.c	2004-07-04 23:02:39 -07:00
@@ -81,7 +81,7 @@
 }
 
 
-/* caller owns root->serialize, and should reset/reinit on error */
+/* caller has locked the root hub, and should reset/reinit on error */
 static int ehci_hub_resume (struct usb_hcd *hcd)
 {
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
diff -Nru a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
--- a/drivers/usb/host/ehci-q.c	2004-07-04 23:02:39 -07:00
+++ b/drivers/usb/host/ehci-q.c	2004-07-04 23:02:39 -07:00
@@ -153,17 +153,9 @@
 			usb_pipein (urb->pipe) ? "in" : "out",
 			token, urb->status);
 
-		/* stall indicates some recovery action is needed */
-		if (urb->status == -EPIPE) {
-			int	pipe = urb->pipe;
-
-			if (!usb_pipecontrol (pipe))
-				usb_endpoint_halt (urb->dev,
-					usb_pipeendpoint (pipe),
-					usb_pipeout (pipe));
-
 		/* if async CSPLIT failed, try cleaning out the TT buffer */
-		} else if (urb->dev->tt && !usb_pipeint (urb->pipe)
+		if (urb->status != -EPIPE
+				&& urb->dev->tt && !usb_pipeint (urb->pipe)
 				&& ((token & QTD_STS_MMF) != 0
 					|| QTD_CERR(token) == 0)
 				&& (!ehci_is_ARC(ehci)
diff -Nru a/drivers/usb/host/hc_simple.c b/drivers/usb/host/hc_simple.c
--- a/drivers/usb/host/hc_simple.c	2004-07-04 23:02:39 -07:00
+++ b/drivers/usb/host/hc_simple.c	2004-07-04 23:02:39 -07:00
@@ -146,11 +146,6 @@
 	if (!urb->dev || !urb->dev->bus || urb->hcpriv)
 		return -EINVAL;
 
-	if (usb_endpoint_halted
-	    (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe))) {
-		printk ("hci_submit_urb: endpoint_halted\n");
-		return -EPIPE;
-	}
 	hci = (hci_t *) urb->dev->bus->hcpriv;
 
 	/* a request to the virtual root hub */
@@ -189,7 +184,7 @@
  *
  * Return: 0 if success or error code 
  **************************************************************************/
-static int hci_unlink_urb (struct urb * urb)
+static int hci_unlink_urb (struct urb * urb, int status)
 {
 	unsigned long flags;
 	hci_t *hci;
@@ -219,45 +214,21 @@
 	if (!list_empty (&urb->urb_list) && urb->status == -EINPROGRESS) {
 		/* URB active? */
 
-		if (urb->transfer_flags & URB_ASYNC_UNLINK) {
-			/* asynchronous with callback */
-			/* relink the urb to the del list */
-			list_move (&urb->urb_list, &hci->del_list);
-			spin_unlock_irqrestore (&usb_urb_lock, flags);
-		} else {
-			/* synchronous without callback */
-
-			add_wait_queue (&hci->waitq, &wait);
-
-			set_current_state (TASK_UNINTERRUPTIBLE);
-			comp = urb->complete;
-			urb->complete = NULL;
-
-			/* relink the urb to the del list */
-			list_move(&urb->urb_list, &hci->del_list);
-
-			spin_unlock_irqrestore (&usb_urb_lock, flags);
-
-			schedule_timeout (HZ / 50);
-
-			if (!list_empty (&urb->urb_list))
-				list_del (&urb->urb_list);
-
-			urb->complete = comp;
-			urb->hcpriv = NULL;
-			remove_wait_queue (&hci->waitq, &wait);
-		}
+		/* asynchronous with callback */
+		/* relink the urb to the del list */
+		list_move (&urb->urb_list, &hci->del_list);
+		urb->status = status;
+		spin_unlock_irqrestore (&usb_urb_lock, flags);
 	} else {
 		/* hcd does not own URB but we keep the driver happy anyway */
 		spin_unlock_irqrestore (&usb_urb_lock, flags);
 
-		if (urb->complete && (urb->transfer_flags & URB_ASYNC_UNLINK)) {
-			urb->status = -ENOENT;
+		if (urb->complete) {
+			urb->status = status;
 			urb->actual_length = 0;
 			urb->complete (urb, NULL);
-			urb->status = 0;
-		} else {
-			urb->status = -ENOENT;
+			if (urb->reject)
+				wake_up (&usb_kill_urb_queue);
 		}
 	}
 
diff -Nru a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
--- a/drivers/usb/host/ohci-hub.c	2004-07-04 23:02:39 -07:00
+++ b/drivers/usb/host/ohci-hub.c	2004-07-04 23:02:39 -07:00
@@ -165,7 +165,7 @@
 
 static int hc_restart (struct ohci_hcd *ohci);
 
-/* caller owns root->serialize */
+/* caller has locked the root hub */
 static int ohci_hub_resume (struct usb_hcd *hcd)
 {
 	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
@@ -301,9 +301,9 @@
 {
 	struct usb_hcd	*hcd = _hcd;
 
-	down (&hcd->self.root_hub->serialize);
+	usb_lock_device (hcd->self.root_hub);
 	(void) ohci_hub_resume (hcd);
-	up (&hcd->self.root_hub->serialize);
+	usb_unlock_device (hcd->self.root_hub);
 }
 
 #else
@@ -381,12 +381,12 @@
 			&& ((OHCI_CTRL_HCFS | OHCI_SCHED_ENABLES)
 					& ohci->hc_control)
 				== OHCI_USB_OPER
-			&& down_trylock (&hcd->self.root_hub->serialize) == 0
+			&& usb_trylock_device (hcd->self.root_hub) == 0
 			) {
 		ohci_vdbg (ohci, "autosuspend\n");
 		(void) ohci_hub_suspend (&ohci->hcd);
 		ohci->hcd.state = USB_STATE_RUNNING;
-		up (&hcd->self.root_hub->serialize);
+		usb_unlock_device (hcd->self.root_hub);
 	}
 #endif
 
diff -Nru a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
--- a/drivers/usb/host/ohci-pci.c	2004-07-04 23:02:39 -07:00
+++ b/drivers/usb/host/ohci-pci.c	2004-07-04 23:02:39 -07:00
@@ -127,9 +127,9 @@
 #ifdef	CONFIG_USB_SUSPEND
 	(void) usb_suspend_device (hcd->self.root_hub);
 #else
-	down (&hcd->self.root_hub->serialize);
+	usb_lock_device (hcd->self.root_hub);
 	(void) ohci_hub_suspend (hcd);
-	up (&hcd->self.root_hub->serialize);
+	usb_unlock_device (hcd->self.root_hub);
 #endif
 
 	/* let things settle down a bit */
@@ -175,9 +175,9 @@
 	/* get extra cleanup even if remote wakeup isn't in use */
 	retval = usb_resume_device (hcd->self.root_hub);
 #else
-	down (&hcd->self.root_hub->serialize);
+	usb_lock_device (hcd->self.root_hub);
 	retval = ohci_hub_resume (hcd);
-	up (&hcd->self.root_hub->serialize);
+	usb_unlock_device (hcd->self.root_hub);
 #endif
 
 	if (retval == 0) {
diff -Nru a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c
--- a/drivers/usb/host/ohci-q.c	2004-07-04 23:02:39 -07:00
+++ b/drivers/usb/host/ohci-q.c	2004-07-04 23:02:39 -07:00
@@ -751,12 +751,6 @@
 
   		cc = TD_CC_GET (tdINFO);
 
-		/* control endpoints only have soft stalls */
-  		if (type != PIPE_CONTROL && cc == TD_CC_STALL)
-			usb_endpoint_halt (urb->dev,
-				usb_pipeendpoint (urb->pipe),
-				usb_pipeout (urb->pipe));
-
 		/* update packet status if needed (short is normally ok) */
 		if (cc == TD_DATAUNDERRUN
 				&& !(urb->transfer_flags & URB_SHORT_NOT_OK))
diff -Nru a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
--- a/drivers/usb/host/uhci-hcd.c	2004-07-04 23:02:39 -07:00
+++ b/drivers/usb/host/uhci-hcd.c	2004-07-04 23:02:39 -07:00
@@ -1120,10 +1120,6 @@
 
 td_error:
 	ret = uhci_map_status(status, uhci_packetout(td_token(td)));
-	if (ret == -EPIPE)
-		/* endpoint has stalled - mark it halted */
-		usb_endpoint_halt(urb->dev, uhci_endpoint(td_token(td)),
-	    			uhci_packetout(td_token(td)));
 
 err:
 	/* 
diff -Nru a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c
--- a/drivers/usb/image/microtek.c	2004-07-04 23:02:39 -07:00
+++ b/drivers/usb/image/microtek.c	2004-07-04 23:02:39 -07:00
@@ -214,8 +214,8 @@
 #ifdef MTS_DO_DEBUG
 
 static inline void mts_debug_dump(struct mts_desc* desc) {
-	MTS_DEBUG("desc at 0x%x: halted = %02x%02x, toggle = %02x%02x\n",
-		  (int)desc,(int)desc->usb_dev->halted[1],(int)desc->usb_dev->halted[0],
+	MTS_DEBUG("desc at 0x%x: toggle = %02x%02x\n",
+		  (int)desc,
 		  (int)desc->usb_dev->toggle[1],(int)desc->usb_dev->toggle[0]
 		);
 	MTS_DEBUG("ep_out=%x ep_response=%x ep_image=%x\n",
@@ -341,12 +341,18 @@
 static int mts_scsi_host_reset (Scsi_Cmnd *srb)
 {
 	struct mts_desc* desc = (struct mts_desc*)(srb->device->host->hostdata[0]);
+	int result, rc;
 
 	MTS_DEBUG_GOT_HERE();
 	mts_debug_dump(desc);
 
-	usb_reset_device(desc->usb_dev); /*FIXME: untested on new reset code */
-	return 0;  /* RANT why here 0 and not SUCCESS */
+	rc = usb_lock_device_for_reset(desc->usb_dev, desc->usb_intf);
+	if (rc < 0)
+		return FAILED;
+	result = usb_reset_device(desc->usb_dev);;
+	if (rc)
+		usb_unlock_device(desc->usb_dev);
+	return result ? FAILED : SUCCESS;
 }
 
 static
@@ -777,6 +783,7 @@
 		goto out_kfree;
 
 	new_desc->usb_dev = dev;
+	new_desc->usb_intf = intf;
 	init_MUTEX(&new_desc->lock);
 
 	/* endpoints */
diff -Nru a/drivers/usb/image/microtek.h b/drivers/usb/image/microtek.h
--- a/drivers/usb/image/microtek.h	2004-07-04 23:02:39 -07:00
+++ b/drivers/usb/image/microtek.h	2004-07-04 23:02:39 -07:00
@@ -31,6 +31,7 @@
 	struct mts_desc *prev;
 
 	struct usb_device *usb_dev;
+	struct usb_interface *usb_intf;
 
 	/* Endpoint addresses */
 	u8 ep_out;
diff -Nru a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
--- a/drivers/usb/input/hid-core.c	2004-07-04 23:02:39 -07:00
+++ b/drivers/usb/input/hid-core.c	2004-07-04 23:02:39 -07:00
@@ -1425,6 +1425,9 @@
 #define USB_VENDOR_ID_GLAB		0x06c2
 #define USB_DEVICE_ID_4_PHIDGETSERVO_30	0x0038
 #define USB_DEVICE_ID_1_PHIDGETSERVO_30	0x0039
+#define USB_DEVICE_ID_8_8_8_IF_KIT	0x0045
+#define USB_DEVICE_ID_0_0_4_IF_KIT	0x0040
+#define USB_DEVICE_ID_0_8_8_IF_KIT	0x0053
 
 #define USB_VENDOR_ID_WISEGROUP		0x0925
 #define USB_DEVICE_ID_1_PHIDGETSERVO_20	0x8101
@@ -1483,8 +1486,13 @@
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 7, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_VOLITO, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PTU, HID_QUIRK_IGNORE },
+
 	{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_4_PHIDGETSERVO_30, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_1_PHIDGETSERVO_30, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_8_8_8_IF_KIT, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_0_4_IF_KIT, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_8_IF_KIT, HID_QUIRK_IGNORE },
+
 	{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_4_PHIDGETSERVO_20, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20, HID_QUIRK_IGNORE },
 
diff -Nru a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
--- a/drivers/usb/storage/scsiglue.c	2004-07-04 23:02:39 -07:00
+++ b/drivers/usb/storage/scsiglue.c	2004-07-04 23:02:39 -07:00
@@ -261,7 +261,7 @@
 static int bus_reset( Scsi_Cmnd *srb )
 {
 	struct us_data *us = (struct us_data *)srb->device->host->hostdata[0];
-	int result;
+	int result, rc;
 
 	US_DEBUGP("%s called\n", __FUNCTION__);
 	if (us->sm_state != US_STATE_IDLE) {
@@ -286,8 +286,16 @@
 		result = -EBUSY;
 		US_DEBUGP("Refusing to reset a multi-interface device\n");
 	} else {
-		result = usb_reset_device(us->pusb_dev);
-		US_DEBUGP("usb_reset_device returns %d\n", result);
+		rc = usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf);
+		if (rc < 0) {
+			US_DEBUGP("unable to lock device for reset: %d\n", rc);
+			result = rc;
+		} else {
+			result = usb_reset_device(us->pusb_dev);
+			if (rc)
+				usb_unlock_device(us->pusb_dev);
+			US_DEBUGP("usb_reset_device returns %d\n", result);
+		}
 	}
 	up(&(us->dev_semaphore));
 
diff -Nru a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
--- a/drivers/usb/storage/transport.c	2004-07-04 23:02:39 -07:00
+++ b/drivers/usb/storage/transport.c	2004-07-04 23:02:39 -07:00
@@ -260,9 +260,7 @@
 		USB_ENDPOINT_HALT, endp,
 		NULL, 0, 3*HZ);
 
-	/* reset the toggles and endpoint flags */
-	usb_endpoint_running(us->pusb_dev, usb_pipeendpoint(pipe),
-		usb_pipeout(pipe));
+	/* reset the endpoint toggle */
 	usb_settoggle(us->pusb_dev, usb_pipeendpoint(pipe),
 		usb_pipeout(pipe), 0);
 
diff -Nru a/include/linux/usb.h b/include/linux/usb.h
--- a/include/linux/usb.h	2004-07-04 23:02:39 -07:00
+++ b/include/linux/usb.h	2004-07-04 23:02:39 -07:00
@@ -61,6 +61,13 @@
 	int extralen;
 };
 
+enum usb_interface_condition {
+	USB_INTERFACE_UNBOUND = 0,
+	USB_INTERFACE_BINDING,
+	USB_INTERFACE_BOUND,
+	USB_INTERFACE_UNBINDING,
+};
+
 /**
  * struct usb_interface - what usb device drivers talk to
  * @altsetting: array of interface structures, one for each alternate
@@ -75,6 +82,8 @@
  *	be unused.  The driver should set this value in the probe()
  *	function of the driver, after it has been assigned a minor
  *	number from the USB core by calling usb_register_dev().
+ * @condition: binding state of the interface: not bound, binding
+ *	(in probe()), bound to a driver, or unbinding (in disconnect())
  * @dev: driver model's view of this device
  * @class_dev: driver model's class view of this device.
  *
@@ -113,6 +122,7 @@
 	unsigned num_altsetting;	/* number of alternate settings */
 
 	int minor;			/* minor number this interface is bound to */
+	enum usb_interface_condition condition;		/* state of binding */
 	struct device dev;		/* interface specific device info */
 	struct class_device *class_dev;
 };
@@ -279,6 +289,17 @@
 
 struct usb_tt;
 
+/**
+ * struct usb_device - kernel's representation of a USB device
+ *
+ * FIXME: Write the kerneldoc!
+ *
+ * WARNING: Drivers should not attempt to manipulate usbdev->serialize
+ * directly.  Instead use usb_lock_device() and usb_unlock_device().
+ *
+ * Usbcore drivers should not set usbdev->state directly.  Instead use
+ * usb_set_device_state().
+ */
 struct usb_device {
 	int		devnum;		/* Address on USB bus */
 	char		devpath [16];	/* Use in messages: /port/port/... */
@@ -291,8 +312,6 @@
 	struct semaphore serialize;
 
 	unsigned int toggle[2];		/* one bit for each endpoint ([0] = IN, [1] = OUT) */
-	unsigned int halted[2];		/* endpoint halts; one bit per endpoint # & direction; */
-					/* [0] = IN, [1] = OUT */
 	int epmaxpacketin[16];		/* INput endpoint specific maximums */
 	int epmaxpacketout[16];		/* OUTput endpoint specific maximums */
 
@@ -332,9 +351,15 @@
 extern struct usb_device *usb_get_dev(struct usb_device *dev);
 extern void usb_put_dev(struct usb_device *dev);
 
-/* mostly for devices emulating SCSI over USB */
+/* for device locking -- don't manipulate usbdev->serialize directly! */
+extern void usb_lock_device(struct usb_device *udev);
+extern int usb_trylock_device(struct usb_device *udev);
+extern int usb_lock_device_for_reset(struct usb_device *udev,
+		struct usb_interface *iface);
+extern void usb_unlock_device(struct usb_device *udev);
+
+/* USB port reset for device reinitialization */
 extern int usb_reset_device(struct usb_device *dev);
-extern int __usb_reset_device(struct usb_device *dev);
 
 extern struct usb_device *usb_find_device(u16 vendor_id, u16 product_id);
 
@@ -657,7 +682,7 @@
  * calling usb_alloc_urb() and freed with a call to usb_free_urb().
  * Initialization may be done using various usb_fill_*_urb() functions.  URBs
  * are submitted using usb_submit_urb(), and pending requests may be canceled
- * using usb_unlink_urb().
+ * using usb_unlink_urb() or usb_kill_urb().
  *
  * Data Transfer Buffers:
  *
@@ -684,7 +709,9 @@
  * All URBs submitted must initialize dev, pipe,
  * transfer_flags (may be zero), complete, timeout (may be zero).
  * The URB_ASYNC_UNLINK transfer flag affects later invocations of
- * the usb_unlink_urb() routine.
+ * the usb_unlink_urb() routine.  Note: Failure to set URB_ASYNC_UNLINK
+ * with usb_unlink_urb() is deprecated.  For synchronous unlinks use
+ * usb_kill_urb() instead.
  *
  * All URBs must also initialize 
  * transfer_buffer and transfer_buffer_length.  They may provide the
@@ -762,6 +789,8 @@
 	void *hcpriv;			/* private data for host controller */
 	struct list_head urb_list;	/* list pointer to all active urbs */
 	int bandwidth;			/* bandwidth for INT/ISO request */
+	atomic_t use_count;		/* concurrent submissions counter */
+	u8 reject;			/* submissions will fail */
 
 	/* public, documented fields in the urb that can be used by drivers */
 	struct usb_device *dev; 	/* (in) pointer to associated device */
@@ -897,6 +926,7 @@
 extern struct urb *usb_get_urb(struct urb *urb);
 extern int usb_submit_urb(struct urb *urb, int mem_flags);
 extern int usb_unlink_urb(struct urb *urb);
+extern void usb_kill_urb(struct urb *urb);
 
 #define HAVE_USB_BUFFERS
 void *usb_buffer_alloc (struct usb_device *dev, size_t size,
@@ -1070,10 +1100,6 @@
 #define usb_gettoggle(dev, ep, out) (((dev)->toggle[out] >> (ep)) & 1)
 #define	usb_dotoggle(dev, ep, out)  ((dev)->toggle[out] ^= (1 << (ep)))
 #define usb_settoggle(dev, ep, out, bit) ((dev)->toggle[out] = ((dev)->toggle[out] & ~(1 << (ep))) | ((bit) << (ep)))
-
-/* Endpoint halt control/status ... likewise USE WITH CAUTION */
-#define usb_endpoint_running(dev, ep, out) ((dev)->halted[out] &= ~(1 << (ep)))
-#define usb_endpoint_halted(dev, ep, out) ((dev)->halted[out] & (1 << (ep)))
 
 
 static inline unsigned int __create_pipe(struct usb_device *dev, unsigned int endpoint)
