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 <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <greg@kroah.com>


 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);
