ChangeSet 1.1760.26.9, 2004/06/24 10:42:03-07:00, stern@rowland.harvard.edu [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: Alan Stern Signed-off-by: Greg Kroah-Hartman drivers/usb/gadget/dummy_hcd.c | 38 ++++++++++++++++++++++++++------------ 1 files changed, 26 insertions(+), 12 deletions(-) diff -Nru a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c --- a/drivers/usb/gadget/dummy_hcd.c 2004-06-29 16:26:11 -07:00 +++ b/drivers/usb/gadget/dummy_hcd.c 2004-06-29 16:26:11 -07:00 @@ -146,8 +146,6 @@ u8 fifo_buf [FIFO_SIZE]; u16 devstatus; - struct hcd_dev *hdev; - /* * MASTER/HOST side support */ @@ -159,6 +157,8 @@ struct completion released; unsigned resuming:1; unsigned long re_timeout; + + struct usb_device *udev; }; static struct dummy *the_controller; @@ -822,7 +822,12 @@ dum = container_of (hcd, struct dummy, hcd); 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; if (usb_pipetype (urb->pipe) == PIPE_CONTROL) urb->error_count = 1; /* mark as a new urb */ @@ -1029,17 +1034,12 @@ static void dummy_timer (unsigned long _dum) { struct dummy *dum = (struct dummy *) _dum; - struct hcd_dev *hdev = dum->hdev; + struct hcd_dev *hdev; struct list_head *entry, *tmp; unsigned long flags; int limit, total; int i; - if (!hdev) { - dev_err (hardware, "timer fired with device gone?\n"); - return; - } - /* simplistic model for one frame's bandwidth */ switch (dum->gadget.speed) { case USB_SPEED_LOW: @@ -1060,6 +1060,14 @@ /* look at each urb queued by the host side driver */ 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++) { if (!ep_name [i]) break; @@ -1331,7 +1339,11 @@ /* want a 1 msec delay here */ 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); } @@ -1568,10 +1580,12 @@ struct urb *urb; size_t size = 0; unsigned long flags; + struct hcd_dev *hdev; spin_lock_irqsave (&dum->lock, flags); - if (dum->hdev) { - list_for_each_entry (urb, &dum->hdev->urb_list, urb_list) { + if (dum->udev) { + hdev = dum->udev->hcpriv; + list_for_each_entry (urb, &hdev->urb_list, urb_list) { size_t temp; temp = show_urb (buf, PAGE_SIZE - size, urb);