patch-2.4.21 linux-2.4.21/drivers/usb/devio.c

Next file: linux-2.4.21/drivers/usb/dsbr100.c
Previous file: linux-2.4.21/drivers/usb/auerswald.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.20/drivers/usb/devio.c linux-2.4.21/drivers/usb/devio.c
@@ -50,6 +50,7 @@
         struct dev_state *ps;
 	struct task_struct *task;
 	unsigned int signr;
+	unsigned int intf;
 	void *userbuffer;
         void *userurb;
         struct urb urb;
@@ -204,8 +205,7 @@
         unsigned long flags;
         
         spin_lock_irqsave(&ps->lock, flags);
-        list_del(&as->asynclist);
-        INIT_LIST_HEAD(&as->asynclist);
+        list_del_init(&as->asynclist);
         spin_unlock_irqrestore(&ps->lock, flags);
 }
 
@@ -217,8 +217,7 @@
         spin_lock_irqsave(&ps->lock, flags);
         if (!list_empty(&ps->async_completed)) {
                 as = list_entry(ps->async_completed.next, struct async, asynclist);
-                list_del(&as->asynclist);
-                INIT_LIST_HEAD(&as->asynclist);
+                list_del_init(&as->asynclist);
         }
         spin_unlock_irqrestore(&ps->lock, flags);
         return as;
@@ -228,19 +227,14 @@
 {
         unsigned long flags;
         struct async *as;
-        struct list_head *p;
 
         spin_lock_irqsave(&ps->lock, flags);
-        for (p = ps->async_pending.next; p != &ps->async_pending; ) {
-                as = list_entry(p, struct async, asynclist);
-                p = p->next;
-                if (as->userurb != userurb)
-                        continue;
-                list_del(&as->asynclist);
-                INIT_LIST_HEAD(&as->asynclist);
-                spin_unlock_irqrestore(&ps->lock, flags);
-                return as;
-        }
+	list_for_each_entry(as, &ps->async_pending, asynclist)
+		if (as->userurb == userurb) {
+			list_del_init(&as->asynclist);
+			spin_unlock_irqrestore(&ps->lock, flags);
+			return as;
+		}
         spin_unlock_irqrestore(&ps->lock, flags);
         return NULL;
 }
@@ -252,8 +246,7 @@
 	struct siginfo sinfo;
 
         spin_lock(&ps->lock);
-        list_del(&as->asynclist);
-        list_add_tail(&as->asynclist, &ps->async_completed);
+        list_move_tail(&as->asynclist, &ps->async_completed);
         spin_unlock(&ps->lock);
         wake_up(&ps->wait);
 	if (as->signr) {
@@ -265,24 +258,42 @@
 	}
 }
 
-static void destroy_all_async(struct dev_state *ps)
+static void destroy_async (struct dev_state *ps, struct list_head *list)
 {
-        struct async *as;
-        unsigned long flags;
+	struct async *as;
+	unsigned long flags;
 
-        spin_lock_irqsave(&ps->lock, flags);
-        while (!list_empty(&ps->async_pending)) {
-                as = list_entry(ps->async_pending.next, struct async, asynclist);
-                list_del(&as->asynclist);
-                INIT_LIST_HEAD(&as->asynclist);
-                spin_unlock_irqrestore(&ps->lock, flags);
-                /* usb_unlink_urb calls the completion handler with status == USB_ST_URB_KILLED */
-                usb_unlink_urb(&as->urb);
-                spin_lock_irqsave(&ps->lock, flags);
-        }
-        spin_unlock_irqrestore(&ps->lock, flags);
-        while ((as = async_getcompleted(ps)))
-                free_async(as);
+	spin_lock_irqsave(&ps->lock, flags);
+	while (!list_empty(list)) {
+		as = list_entry(list->next, struct async, asynclist);
+		list_del_init(&as->asynclist);
+		spin_unlock_irqrestore(&ps->lock, flags);
+		/* usb_unlink_urb calls the completion handler with status == USB_ST_URB_KILLED */
+		usb_unlink_urb(&as->urb);
+		spin_lock_irqsave(&ps->lock, flags);
+	}
+	spin_unlock_irqrestore(&ps->lock, flags);
+	while ((as = async_getcompleted(ps)))
+		free_async(as);
+}
+
+static void destroy_async_on_interface (struct dev_state *ps, unsigned int intf)
+{
+	struct list_head *p, *q, hitlist;
+	unsigned long flags;
+
+	INIT_LIST_HEAD(&hitlist);
+	spin_lock_irqsave(&ps->lock, flags);
+	list_for_each_safe(p, q, &ps->async_pending)
+		if (intf == list_entry(p, struct async, asynclist)->intf)
+			list_move_tail(p, &hitlist);
+	spin_unlock_irqrestore(&ps->lock, flags);
+	destroy_async(ps, &hitlist);
+}
+
+static inline void destroy_all_async(struct dev_state *ps)
+{
+	destroy_async(ps, &ps->async_pending);
 }
 
 /*
@@ -519,8 +530,7 @@
 	unsigned int i;
 
 	lock_kernel();
-	list_del(&ps->list);
-	INIT_LIST_HEAD(&ps->list);
+	list_del_init(&ps->list);
 	if (ps->dev) {
 		for (i = 0; ps->ifclaimed && i < 8*sizeof(ps->ifclaimed); i++)
 			if (test_bit(i, &ps->ifclaimed))
@@ -775,6 +785,7 @@
 	struct usb_ctrlrequest *dr = NULL;
 	unsigned int u, totlen, isofrmlen;
 	int ret;
+	int intf = -1;
 
 	if (copy_from_user(&uurb, arg, sizeof(uurb)))
 		return -EFAULT;
@@ -786,9 +797,9 @@
 	if (uurb.signr != 0 && (uurb.signr < SIGRTMIN || uurb.signr > SIGRTMAX))
 		return -EINVAL;
 	if (!(uurb.type == USBDEVFS_URB_TYPE_CONTROL && (uurb.endpoint & ~USB_ENDPOINT_DIR_MASK) == 0)) {
-		if ((ret = findintfep(ps->dev, uurb.endpoint)) < 0)
-			return ret;
-		if ((ret = checkintf(ps, ret)))
+		if ((intf = findintfep(ps->dev, uurb.endpoint)) < 0)
+			return intf;
+		if ((ret = checkintf(ps, intf)))
 			return ret;
 	}
 	switch(uurb.type) {
@@ -909,6 +920,7 @@
 	else
 		as->userbuffer = NULL;
 	as->signr = uurb.signr;
+	as->intf = intf;
 	as->task = current;
 	if (!(uurb.endpoint & USB_DIR_IN)) {
 		if (copy_from_user(as->urb.transfer_buffer, uurb.buffer, as->urb.transfer_buffer_length)) {
@@ -1054,7 +1066,10 @@
 		return -EFAULT;
 	if ((ret = findintfif(ps->dev, intf)) < 0)
 		return ret;
-	return releaseintf(ps, intf);
+	if ((ret = releaseintf(ps, intf)) < 0)
+		return ret;
+	destroy_async_on_interface (ps, intf);
+	return 0;
 }
 
 static int proc_ioctl (struct dev_state *ps, void *arg)

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)