Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6:
  USB: prevent autosuspend during hub initialization
  USB: Unusual dev for the "Kyocera / Contax SL300R T*" digital camera.
  USB: usbtmc: Use explicit unsigned type for input buffer instead of char*
  USB: fix crash when URBs are unlinked after the device is gone
This commit is contained in:
Linus Torvalds 2008-10-30 11:49:12 -07:00
commit 52e8e19b01
6 changed files with 67 additions and 4 deletions

View File

@ -133,7 +133,7 @@ static int usbtmc_release(struct inode *inode, struct file *file)
static int usbtmc_ioctl_abort_bulk_in(struct usbtmc_device_data *data)
{
char *buffer;
u8 *buffer;
struct device *dev;
int rv;
int n;

View File

@ -106,6 +106,9 @@ static DEFINE_SPINLOCK(hcd_root_hub_lock);
/* used when updating an endpoint's URB list */
static DEFINE_SPINLOCK(hcd_urb_list_lock);
/* used to protect against unlinking URBs after the device is gone */
static DEFINE_SPINLOCK(hcd_urb_unlink_lock);
/* wait queue for synchronous unlinks */
DECLARE_WAIT_QUEUE_HEAD(usb_kill_urb_queue);
@ -1376,10 +1379,25 @@ static int unlink1(struct usb_hcd *hcd, struct urb *urb, int status)
int usb_hcd_unlink_urb (struct urb *urb, int status)
{
struct usb_hcd *hcd;
int retval;
int retval = -EIDRM;
unsigned long flags;
hcd = bus_to_hcd(urb->dev->bus);
retval = unlink1(hcd, urb, status);
/* Prevent the device and bus from going away while
* the unlink is carried out. If they are already gone
* then urb->use_count must be 0, since disconnected
* devices can't have any active URBs.
*/
spin_lock_irqsave(&hcd_urb_unlink_lock, flags);
if (atomic_read(&urb->use_count) > 0) {
retval = 0;
usb_get_dev(urb->dev);
}
spin_unlock_irqrestore(&hcd_urb_unlink_lock, flags);
if (retval == 0) {
hcd = bus_to_hcd(urb->dev->bus);
retval = unlink1(hcd, urb, status);
usb_put_dev(urb->dev);
}
if (retval == 0)
retval = -EINPROGRESS;
@ -1528,6 +1546,17 @@ void usb_hcd_disable_endpoint(struct usb_device *udev,
hcd->driver->endpoint_disable(hcd, ep);
}
/* Protect against drivers that try to unlink URBs after the device
* is gone, by waiting until all unlinks for @udev are finished.
* Since we don't currently track URBs by device, simply wait until
* nothing is running in the locked region of usb_hcd_unlink_urb().
*/
void usb_hcd_synchronize_unlinks(struct usb_device *udev)
{
spin_lock_irq(&hcd_urb_unlink_lock);
spin_unlock_irq(&hcd_urb_unlink_lock);
}
/*-------------------------------------------------------------------------*/
/* called in any context */

View File

@ -232,6 +232,7 @@ extern void usb_hcd_flush_endpoint(struct usb_device *udev,
struct usb_host_endpoint *ep);
extern void usb_hcd_disable_endpoint(struct usb_device *udev,
struct usb_host_endpoint *ep);
extern void usb_hcd_synchronize_unlinks(struct usb_device *udev);
extern int usb_hcd_get_frame_number(struct usb_device *udev);
extern struct usb_hcd *usb_create_hcd(const struct hc_driver *driver,

View File

@ -659,6 +659,9 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
PREPARE_DELAYED_WORK(&hub->init_work, hub_init_func2);
schedule_delayed_work(&hub->init_work,
msecs_to_jiffies(delay));
/* Suppress autosuspend until init is done */
to_usb_interface(hub->intfdev)->pm_usage_cnt = 1;
return; /* Continues at init2: below */
} else {
hub_power_on(hub, true);
@ -1429,6 +1432,7 @@ void usb_disconnect(struct usb_device **pdev)
*/
dev_dbg (&udev->dev, "unregistering device\n");
usb_disable_device(udev, 0);
usb_hcd_synchronize_unlinks(udev);
usb_unlock_device(udev);

View File

@ -474,6 +474,12 @@ EXPORT_SYMBOL_GPL(usb_submit_urb);
* indicating that the request has been canceled (rather than any other
* code).
*
* Drivers should not call this routine or related routines, such as
* usb_kill_urb() or usb_unlink_anchored_urbs(), after their disconnect
* method has returned. The disconnect function should synchronize with
* a driver's I/O routines to insure that all URB-related activity has
* completed before it returns.
*
* This request is always asynchronous. Success is indicated by
* returning -EINPROGRESS, at which time the URB will probably not yet
* have been given back to the device driver. When it is eventually
@ -550,6 +556,9 @@ EXPORT_SYMBOL_GPL(usb_unlink_urb);
* 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().
*
* This routine should not be called by a driver after its disconnect
* method has returned.
*/
void usb_kill_urb(struct urb *urb)
{
@ -588,6 +597,9 @@ EXPORT_SYMBOL_GPL(usb_kill_urb);
* 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().
*
* This routine should not be called by a driver after its disconnect
* method has returned.
*/
void usb_poison_urb(struct urb *urb)
{
@ -622,6 +634,9 @@ EXPORT_SYMBOL_GPL(usb_unpoison_urb);
*
* this allows all outstanding URBs to be killed starting
* from the back of the queue
*
* This routine should not be called by a driver after its disconnect
* method has returned.
*/
void usb_kill_anchored_urbs(struct usb_anchor *anchor)
{
@ -651,6 +666,9 @@ EXPORT_SYMBOL_GPL(usb_kill_anchored_urbs);
* this allows all outstanding URBs to be poisoned starting
* from the back of the queue. Newly added URBs will also be
* poisoned
*
* This routine should not be called by a driver after its disconnect
* method has returned.
*/
void usb_poison_anchored_urbs(struct usb_anchor *anchor)
{
@ -672,6 +690,7 @@ void usb_poison_anchored_urbs(struct usb_anchor *anchor)
spin_unlock_irq(&anchor->lock);
}
EXPORT_SYMBOL_GPL(usb_poison_anchored_urbs);
/**
* usb_unlink_anchored_urbs - asynchronously cancel transfer requests en masse
* @anchor: anchor the requests are bound to
@ -680,6 +699,9 @@ EXPORT_SYMBOL_GPL(usb_poison_anchored_urbs);
* from the back of the queue. This function is asynchronous.
* The unlinking is just tiggered. It may happen after this
* function has returned.
*
* This routine should not be called by a driver after its disconnect
* method has returned.
*/
void usb_unlink_anchored_urbs(struct usb_anchor *anchor)
{

View File

@ -333,6 +333,13 @@ UNUSUAL_DEV( 0x0482, 0x0103, 0x0100, 0x0100,
"Finecam S5",
US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY),
/* Patch submitted by Jens Taprogge <jens.taprogge@taprogge.org> */
UNUSUAL_DEV( 0x0482, 0x0107, 0x0100, 0x0100,
"Kyocera",
"CONTAX SL300R T*",
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_FIX_CAPACITY | US_FL_NOT_LOCKABLE),
/* Reported by Paul Stewart <stewart@wetlogic.net>
* This entry is needed because the device reports Sub=ff */
UNUSUAL_DEV( 0x04a4, 0x0004, 0x0001, 0x0001,