> Applied, thanks. Could you also make a 2.5 version of this patch?
Here is the 2.5 version. It is essentially the same as the 2.4 version.
I included the white-space changes just to annoy Dave!
Duncan.
PS: I used "extern __inline__" to be consistent with the rest of devio.c.
Why not just use "extern inline"? I thought __inline__ was only needed
in header files...
--- linux-2.5/drivers/usb/core/devio.c.orig 2002-11-22 12:42:31.000000000 +0100
+++ linux-2.5/drivers/usb/core/devio.c 2002-11-22 12:12:01.000000000 +0100
@@ -53,6 +53,7 @@
struct dev_state *ps;
struct task_struct *task;
unsigned int signr;
+ unsigned int intf;
void *userbuffer;
void *userurb;
struct urb *urb;
@@ -273,23 +274,47 @@
}
}
-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_init(&as->asynclist);
- spin_unlock_irqrestore(&ps->lock, flags);
+ 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 == -ENOENT */
- 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);
+ 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 async *as;
+ struct list_head *p, hitlist;
+ unsigned long flags;
+
+ INIT_LIST_HEAD(&hitlist);
+ 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->intf == intf)
+ list_move_tail(&as->asynclist, &hitlist);
+ }
+ spin_unlock_irqrestore(&ps->lock, flags);
+ destroy_async(ps, &hitlist);
+}
+
+extern __inline__ void destroy_all_async(struct dev_state *ps)
+{
+ destroy_async(ps, &ps->async_pending);
}
/*
@@ -751,7 +776,7 @@
struct async *as;
struct usb_ctrlrequest *dr = NULL;
unsigned int u, totlen, isofrmlen;
- int ret, interval = 0;
+ int ret, interval = 0, intf = -1;
if (copy_from_user(&uurb, arg, sizeof(uurb)))
return -EFAULT;
@@ -763,9 +788,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) {
@@ -889,6 +914,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)) {
@@ -1035,7 +1061,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)