Am Mittwoch, 28. April 2004 22:27 schrieb Alan Stern:
> > > finished. That's why usb_wait_for_urb() is needed.
> >
> > But is very poorly implemented.
>
> Can you come up with something better in terms of both space and time?
Good question. How do you like this draft in terms of approach?
--- include/linux/usb.h.alt 2004-04-29 14:54:17.000000000 +0200
+++ include/linux/usb.h 2004-04-29 15:33:37.000000000 +0200
@@ -537,6 +537,13 @@
#define URB_ZERO_PACKET 0x0040 /* Finish bulk OUTs with short packet
*/
#define URB_NO_INTERRUPT 0x0080 /* HINT: no non-error interrupt needed */
+/*
+ * urb->phase
+ */
+#define PHASE_IDLE 0
+#define PHASE_DOING 1
+#define PHASE_DONE 2
+
struct usb_iso_packet_descriptor {
unsigned int offset;
unsigned int length; /* expected length */
@@ -722,6 +729,8 @@
void *hcpriv; /* private data for host controller */
struct list_head urb_list; /* list pointer to all active urbs */
int bandwidth; /* bandwidth for INT/ISO request */
+ wait_queue_head_t handler_queue;/* waiting for completion handlers */
+ int phase;
/* public, documented fields in the urb that can be used by drivers */
struct usb_device *dev; /* (in) pointer to associated device */
--- drivers/usb/core/hcd.c.alt 2004-04-29 15:15:06.000000000 +0200
+++ drivers/usb/core/hcd.c 2004-04-29 17:34:02.422824168 +0200
@@ -1185,6 +1185,7 @@
* (urb lock, then hcd_data_lock) in case some other CPU is now
* unlinking it.
*/
+rekill:
spin_lock_irqsave (&urb->lock, flags);
spin_lock (&hcd_data_lock);
@@ -1198,7 +1199,10 @@
hcd = urb->dev->bus->hcpriv;
if (!dev || !hcd) {
retval = -ENODEV;
- goto done;
+ if (urb->phase == PHASE_IDLE)
+ goto done;
+ else
+ goto maybe_wait;
}
/* running ~= hc unlink handshake works (irq, timer, etc)
@@ -1214,7 +1218,10 @@
}
if (tmp != &urb->urb_list) {
retval = -EIDRM;
- goto done;
+ if (urb->phase == PHASE_IDLE)
+ goto done;
+ else
+ goto maybe_wait;
}
/* Any status except -EINPROGRESS means something already started to
@@ -1224,7 +1231,7 @@
*/
if (urb->status != -EINPROGRESS) {
retval = -EBUSY;
- goto done;
+ goto maybe_wait;
}
/* PCI IRQ setup can easily be broken so that USB controllers
@@ -1279,7 +1286,10 @@
urb->context = splice.context;
spin_unlock_irqrestore (&urb->lock, flags);
}
- goto bye;
+ if (urb->phase == PHASE_IDLE)
+ goto bye;
+ else
+ goto wait;
}
}
@@ -1297,6 +1307,16 @@
if (retval != -EIDRM && sys && sys->driver)
dev_dbg (sys, "hcd_unlink_urb %p fail %d\n", urb, retval);
return retval;
+maybe_wait:
+ spin_unlock (&hcd_data_lock);
+ spin_unlock_irqrestore (&urb->lock, flags);
+wait:
+ wait_event(urb->handler_queue, urb->phase != PHASE_IDLE);
+ if (urb->phase == PHASE_DOING)
+ /* the mother has escaped
+ we go for the child */
+ goto rekill;
+ return retval;
}
/*-------------------------------------------------------------------------*/
@@ -1474,6 +1494,7 @@
// hcd_monitor_hook(MONITOR_URB_FINISH, urb, dev)
// It would catch exit/unlink paths for all urbs.
+ urb->phase = PHASE_DONE;
/* lower level hcd code should use *_dma exclusively */
if (hcd->self.controller->dma_mask) {
if (usb_pipecontrol (urb->pipe)
@@ -1493,6 +1514,9 @@
/* pass ownership to the completion handler */
urb->complete (urb, regs);
+ if (urb->phase != PHASE_DOING) /* we have not been resubmitted */
+ urb->phase = PHASE_IDLE;
+ wake_up(&urb->handler_queue);
usb_put_urb (urb);
}
EXPORT_SYMBOL (usb_hcd_giveback_urb);
--- drivers/usb/core/urb.c.alt 2004-04-29 15:13:45.000000000 +0200
+++ drivers/usb/core/urb.c 2004-04-29 15:36:23.000000000 +0200
@@ -33,6 +33,7 @@
memset(urb, 0, sizeof(*urb));
urb->count = (atomic_t)ATOMIC_INIT(1);
spin_lock_init(&urb->lock);
+ init_waitqueue_head(&urb->handler_queue);
}
}
@@ -383,7 +384,8 @@
temp >>= 1;
urb->interval = temp;
}
-
+
+ urb->phase = PHASE_DOING;
return op->submit_urb (urb, mem_flags);
}
-------------------------------------------------------
This SF.Net email is sponsored by: Oracle 10g
Get certified on the hottest thing ever to hit the market... Oracle 10g.
Take an Oracle 10g class now, and we'll give you the exam FREE.
http://ads.osdn.com/?ad_id=3149&alloc_id=8166&op=click
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel