Commit a29c78b8 authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman

[PATCH] USB: Imiprove usb_device tracking in dummy_hcd

A tricky problem the dummy_hcd driver has to solve is keeping track of the
usb_device structure that corresponds to a registered gadget.  Right now
that's not done very robustly.  This patch stores the address of the
structure when a new URB is submitted and also acquires a reference to
make sure that completing the final URB won't deallocate the structure
before dummy_hcd is through with it.
Signed-off-by: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <greg@kroah.com>
parent 5153655b
...@@ -146,8 +146,6 @@ struct dummy { ...@@ -146,8 +146,6 @@ struct dummy {
u8 fifo_buf [FIFO_SIZE]; u8 fifo_buf [FIFO_SIZE];
u16 devstatus; u16 devstatus;
struct hcd_dev *hdev;
/* /*
* MASTER/HOST side support * MASTER/HOST side support
*/ */
...@@ -159,6 +157,8 @@ struct dummy { ...@@ -159,6 +157,8 @@ struct dummy {
struct completion released; struct completion released;
unsigned resuming:1; unsigned resuming:1;
unsigned long re_timeout; unsigned long re_timeout;
struct usb_device *udev;
}; };
static struct dummy *the_controller; static struct dummy *the_controller;
...@@ -822,7 +822,12 @@ static int dummy_urb_enqueue ( ...@@ -822,7 +822,12 @@ static int dummy_urb_enqueue (
dum = container_of (hcd, struct dummy, hcd); dum = container_of (hcd, struct dummy, hcd);
spin_lock_irqsave (&dum->lock, flags); spin_lock_irqsave (&dum->lock, flags);
dum->hdev = urb->dev->hcpriv; if (!dum->udev) {
dum->udev = urb->dev;
usb_get_dev (dum->udev);
} else if (unlikely (dum->udev != urb->dev))
dev_err (hardware, "usb_device address has changed!\n");
urb->hcpriv = dum; urb->hcpriv = dum;
if (usb_pipetype (urb->pipe) == PIPE_CONTROL) if (usb_pipetype (urb->pipe) == PIPE_CONTROL)
urb->error_count = 1; /* mark as a new urb */ urb->error_count = 1; /* mark as a new urb */
...@@ -1029,17 +1034,12 @@ static struct dummy_ep *find_endpoint (struct dummy *dum, u8 address) ...@@ -1029,17 +1034,12 @@ static struct dummy_ep *find_endpoint (struct dummy *dum, u8 address)
static void dummy_timer (unsigned long _dum) static void dummy_timer (unsigned long _dum)
{ {
struct dummy *dum = (struct dummy *) _dum; struct dummy *dum = (struct dummy *) _dum;
struct hcd_dev *hdev = dum->hdev; struct hcd_dev *hdev;
struct list_head *entry, *tmp; struct list_head *entry, *tmp;
unsigned long flags; unsigned long flags;
int limit, total; int limit, total;
int i; int i;
if (!hdev) {
dev_err (hardware, "timer fired with device gone?\n");
return;
}
/* simplistic model for one frame's bandwidth */ /* simplistic model for one frame's bandwidth */
switch (dum->gadget.speed) { switch (dum->gadget.speed) {
case USB_SPEED_LOW: case USB_SPEED_LOW:
...@@ -1060,6 +1060,14 @@ static void dummy_timer (unsigned long _dum) ...@@ -1060,6 +1060,14 @@ static void dummy_timer (unsigned long _dum)
/* look at each urb queued by the host side driver */ /* look at each urb queued by the host side driver */
spin_lock_irqsave (&dum->lock, flags); spin_lock_irqsave (&dum->lock, flags);
if (!dum->udev) {
dev_err (hardware, "timer fired with no URBs pending?\n");
spin_unlock_irqrestore (&dum->lock, flags);
return;
}
hdev = dum->udev->hcpriv;
for (i = 0; i < DUMMY_ENDPOINTS; i++) { for (i = 0; i < DUMMY_ENDPOINTS; i++) {
if (!ep_name [i]) if (!ep_name [i])
break; break;
...@@ -1331,7 +1339,11 @@ static void dummy_timer (unsigned long _dum) ...@@ -1331,7 +1339,11 @@ static void dummy_timer (unsigned long _dum)
/* want a 1 msec delay here */ /* want a 1 msec delay here */
if (!list_empty (&hdev->urb_list)) if (!list_empty (&hdev->urb_list))
mod_timer (&dum->timer, jiffies + 1); mod_timer (&dum->timer, jiffies + msecs_to_jiffies(1));
else {
usb_put_dev (dum->udev);
dum->udev = NULL;
}
spin_unlock_irqrestore (&dum->lock, flags); spin_unlock_irqrestore (&dum->lock, flags);
} }
...@@ -1568,10 +1580,12 @@ show_urbs (struct device *dev, char *buf) ...@@ -1568,10 +1580,12 @@ show_urbs (struct device *dev, char *buf)
struct urb *urb; struct urb *urb;
size_t size = 0; size_t size = 0;
unsigned long flags; unsigned long flags;
struct hcd_dev *hdev;
spin_lock_irqsave (&dum->lock, flags); spin_lock_irqsave (&dum->lock, flags);
if (dum->hdev) { if (dum->udev) {
list_for_each_entry (urb, &dum->hdev->urb_list, urb_list) { hdev = dum->udev->hcpriv;
list_for_each_entry (urb, &hdev->urb_list, urb_list) {
size_t temp; size_t temp;
temp = show_urb (buf, PAGE_SIZE - size, urb); temp = show_urb (buf, PAGE_SIZE - size, urb);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment