Hi all,
this patch (2.3.99pre9_2) for usb-ohci adds asynchronous
usb_unlink_urb support (USB_ASYNC_UNLINK flag).
Due to the lack of a appropriate driver it is not tested.
If anyone works on a driver with async unlink and
has a OHCI then please test it.
Other features of usb-ohci that are missing/different to the
Programming Guide for Linux USB Devices v 1.23 by Detlef Fliegl:
transfer flags:
- USB_DISABLE_SPD ... supported
- USB_URB_EARLY_COMPLETE ... not supported:
this would allow concurrent access (HC + CPU) to the data buffer
- USB_ISO_ASAP ... supported
- USB_ASYNC_UNLINK ... see patch
- USB_TIMEOUT_KILLED ... not supported yet, high priority
- USB_QUEUE_BULK ... flag not supported, always on
urb-fields:
- next: basic support for ISOC, no support for BULK
- INT-transfers,
start_frame: not supported yet (auto load-balancing)
interval 0 : not supported yet
- timeout: not supported yet: see flags
Roman
--- usb.org/usb-ohci.c Sun May 14 14:37:57 2000
+++ usb/usb-ohci.c Mon May 22 00:18:12 2000
@@ -92,7 +92,6 @@
kfree (urb->hcpriv);
urb->hcpriv = NULL;
- wake_up (&op_wakeup);
}
/*-------------------------------------------------------------------------*/
@@ -493,6 +492,8 @@
urb->start_frame = ((ed->state == ED_OPER)? (ed->last_iso + 1):
(le16_to_cpu
(ohci->hcca.frame_no) + 10)) & 0xffff;
}
+ urb->status = USB_ST_URB_PENDING;
+ urb->actual_length = 0;
if (ed->state != ED_OPER) /* link the ed into a chain if is not already */
ep_link (ohci, ed);
@@ -529,6 +530,8 @@
urb_print (urb, "UNLINK", 1);
#endif
+ usb_dec_dev_use (urb->dev);
+
if (usb_pipedevice (urb->pipe) == ohci->rh.devnum)
return rh_unlink_urb (urb); /* a request to the virtual root hub */
@@ -546,19 +549,23 @@
ep_rm_ed (urb->dev, urb_priv->ed);
urb_priv->ed->state |= ED_URB_DEL;
spin_unlock_irqrestore (&usb_ed_lock, flags);
-
- add_wait_queue (&op_wakeup, &wait);
- current->state = TASK_UNINTERRUPTIBLE;
- if (!schedule_timeout (HZ / 10)) /* wait until all TDs are
deleted */
- err("unlink URB timeout!");
- remove_wait_queue (&op_wakeup, &wait);
- } else
+ if (!(urb->transfer_flags & USB_ASYNC_UNLINK)) {
+ add_wait_queue (&op_wakeup, &wait);
+ current->state = TASK_UNINTERRUPTIBLE;
+ if (!schedule_timeout (HZ / 10)) /* wait until all TDs
+are deleted */
+ err("unlink URB timeout!");
+ remove_wait_queue (&op_wakeup, &wait);
+ urb->status = -ENOENT;
+ } else
+ urb->status = -EINPROGRESS;
+ } else {
urb_rm_priv (urb);
-
- urb->status = -ENOENT; // mark urb as killed
- if (urb->complete)
- urb->complete ((struct urb *) urb);
- usb_dec_dev_use (urb->dev);
+ if (urb->complete && (urb->transfer_flags & USB_ASYNC_UNLINK))
+{
+ urb->complete (urb);
+ urb->status = 0;
+ } else
+ urb->status = -ENOENT;
+ }
}
return 0;
}
@@ -967,7 +974,7 @@
/* prepare a TD */
-static void td_fill (unsigned int info, void * data, int len, urb_t * urb, int type,
int index)
+static void td_fill (unsigned int info, void * data, int len, urb_t * urb, int index)
{
volatile td_t * td, * td_pt;
urb_priv_t * urb_priv = urb->hcpriv;
@@ -984,7 +991,6 @@
td->index = index;
td->urb = urb;
td->hwINFO = cpu_to_le32 (info);
- td->type = type;
if ((td->ed->type & 3) == PIPE_ISOCHRONOUS) {
td->hwCBP = cpu_to_le32 (((!data || !len)?
0 : virt_to_bus
(data)) & 0xFFFFF000);
@@ -1031,12 +1037,12 @@
info = usb_pipeout (urb->pipe)?
TD_CC | TD_DP_OUT : TD_CC | TD_DP_IN ;
while(data_len > 4096) {
- td_fill (info | (cnt? TD_T_TOGGLE:toggle), data, 4096,
urb, (cnt? 0: ST_ADDR) | ADD_LEN, cnt);
+ td_fill (info | (cnt? TD_T_TOGGLE:toggle), data, 4096,
+urb, cnt);
data += 4096; data_len -= 4096; cnt++;
}
info = usb_pipeout (urb->pipe)?
TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ;
- td_fill (info | (cnt? TD_T_TOGGLE:toggle), data, data_len,
urb, (cnt? 0: ST_ADDR) | ADD_LEN, cnt);
+ td_fill (info | (cnt? TD_T_TOGGLE:toggle), data, data_len,
+urb, cnt);
cnt++;
writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list
*/
break;
@@ -1044,20 +1050,20 @@
case PIPE_INTERRUPT:
info = usb_pipeout (urb->pipe)?
TD_CC | TD_DP_OUT | toggle: TD_CC | TD_R | TD_DP_IN |
toggle;
- td_fill (info, data, data_len, urb, ST_ADDR | ADD_LEN, cnt++);
+ td_fill (info, data, data_len, urb, cnt++);
break;
case PIPE_CONTROL:
info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
- td_fill (info, ctrl, 8, urb, ST_ADDR, cnt++);
+ td_fill (info, ctrl, 8, urb, cnt++);
if (data_len > 0) {
info = usb_pipeout (urb->pipe)?
TD_CC | TD_R | TD_DP_OUT | TD_T_DATA1 : TD_CC
| TD_R | TD_DP_IN | TD_T_DATA1;
- td_fill (info, data, data_len, urb, ADD_LEN, cnt++);
+ td_fill (info, data, data_len, urb, cnt++);
}
info = usb_pipeout (urb->pipe)?
TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT |
TD_T_DATA1;
- td_fill (info, NULL, 0, urb, 0, cnt++);
+ td_fill (info, NULL, 0, urb, cnt++);
writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control
list */
break;
@@ -1065,7 +1071,7 @@
for (cnt = 0; cnt < urb->number_of_packets; cnt++) {
td_fill (TD_CC|TD_ISO | ((urb->start_frame + cnt) &
0xffff),
(__u8 *) data +
urb->iso_frame_desc[cnt].offset,
- urb->iso_frame_desc[cnt].length, urb, (cnt? 0:
ST_ADDR) | ADD_LEN, cnt);
+ urb->iso_frame_desc[cnt].length, urb, cnt);
}
break;
}
@@ -1076,7 +1082,55 @@
/*-------------------------------------------------------------------------*
* Done List handling functions
*-------------------------------------------------------------------------*/
-
+
+
+/* calculate the transfer length and update the urb */
+
+static void dl_transfer_length(td_t * td)
+{
+ __u32 tdINFO, tdBE, tdCBP;
+ __u16 tdPSW;
+ urb_t * urb = td->urb;
+ urb_priv_t * urb_priv = urb->hcpriv;
+ int dlen = 0;
+ int cc = 0;
+
+ tdINFO = le32_to_cpup (&td->hwINFO);
+ tdBE = le32_to_cpup (&td->hwBE);
+ tdCBP = le32_to_cpup (&td->hwCBP);
+
+
+ if (tdINFO & TD_ISO) {
+ tdPSW = le16_to_cpu (td->hwPSW[0]);
+ cc = (tdPSW >> 12) & 0xF;
+ if (cc < 0xE) {
+ if (usb_pipeout(urb->pipe)) {
+ dlen = urb->iso_frame_desc[td->index].length;
+ } else {
+ dlen = tdPSW & 0x3ff;
+ }
+ urb->actual_length += dlen;
+ urb->iso_frame_desc[td->index].actual_length = dlen;
+ if (!(urb->transfer_flags & USB_DISABLE_SPD) && (cc ==
+TD_DATAUNDERRUN))
+ cc = TD_CC_NOERROR;
+
+ urb->iso_frame_desc[td->index].status = cc_to_error[cc];
+ }
+ } else { /* BULK, INT, CONTROL DATA */
+ if (!(usb_pipetype (urb->pipe) == PIPE_CONTROL &&
+ ((td->index == 0) || (td->index == urb_priv->length -
+1)))) {
+ if (tdBE != 0) {
+ if (td->hwCBP == 0)
+ urb->actual_length = bus_to_virt (tdBE) -
+urb->transfer_buffer + 1;
+ else
+ urb->actual_length = bus_to_virt (tdCBP) -
+urb->transfer_buffer;
+ }
+ }
+ }
+}
+
+/*-------------------------------------------------------------------------*/
+
/* replies to the request have to be on a FIFO basis so
* we reverse the reversed done-list */
@@ -1130,6 +1184,7 @@
unsigned long flags;
ed_t * ed;
__u32 edINFO;
+ __u32 tdINFO;
td_t * td = NULL, * td_next = NULL, * tdHeadP = NULL, * tdTailP;
__u32 * td_p;
int ctrl = 0, bulk = 0;
@@ -1141,16 +1196,25 @@
tdHeadP = bus_to_virt (le32_to_cpup (&ed->hwHeadP) & 0xfffffff0);
edINFO = le32_to_cpup (&ed->hwINFO);
td_p = &ed->hwHeadP;
-
+
for (td = tdHeadP; td != tdTailP; td = td_next) {
urb_t * urb = td->urb;
urb_priv_t * urb_priv = td->urb->hcpriv;
td_next = bus_to_virt (le32_to_cpup (&td->hwNextTD) &
0xfffffff0);
if ((urb_priv->state == URB_DEL) || (ed->state & ED_DEL)) {
+ tdINFO = le32_to_cpup (&td->hwINFO);
+ if (TD_CC_GET (tdINFO) < 0xE) dl_transfer_length (td);
*td_p = td->hwNextTD | (*td_p & cpu_to_le32 (0x3));
if(++ (urb_priv->td_cnt) == urb_priv->length)
urb_rm_priv (urb);
+ if (urb->transfer_flags & USB_ASYNC_UNLINK) {
+ usb_dec_dev_use (urb->dev);
+ urb->status = -ECONNRESET;
+ urb->complete (urb);
+ } else {
+ wake_up (&op_wakeup);
+ }
} else {
td_p = &td->hwNextTD;
}
@@ -1167,7 +1231,7 @@
}
else {
ed->state &= ~ED_URB_DEL;
- ed->hwINFO &= ~cpu_to_le32 (OHCI_ED_SKIP);
+ ed->hwINFO &= ~cpu_to_le32 (OHCI_ED_SKIP);
}
if ((ed->type & 3) == CTRL) ctrl |= 1;
@@ -1185,6 +1249,8 @@
spin_unlock_irqrestore (&usb_ed_lock, flags);
}
+
+
/*-------------------------------------------------------------------------*/
/* td done list */
@@ -1193,12 +1259,11 @@
{
td_t * td_list_next = NULL;
ed_t * ed;
- int dlen = 0;
int cc = 0;
urb_t * urb;
urb_priv_t * urb_priv;
- __u32 tdINFO, tdBE, tdCBP, edHeadP, edTailP;
- __u16 tdPSW;
+ __u32 tdINFO, edHeadP, edTailP;
+
unsigned long flags;
while (td_list) {
@@ -1207,40 +1272,11 @@
urb = td_list->urb;
urb_priv = urb->hcpriv;
tdINFO = le32_to_cpup (&td_list->hwINFO);
- tdBE = le32_to_cpup (&td_list->hwBE);
- tdCBP = le32_to_cpup (&td_list->hwCBP);
ed = td_list->ed;
- if (td_list->type & ST_ADDR)
- urb->actual_length = 0;
-
- if (td_list->type & ADD_LEN) { /* accumulate length of multi td
transfers */
- if (tdINFO & TD_ISO) {
- tdPSW = le16_to_cpu (td_list->hwPSW[0]);
- cc = (tdPSW >> 12) & 0xF;
- if (cc < 0xE) {
- if (usb_pipeout(urb->pipe)) {
- dlen =
urb->iso_frame_desc[td_list->index].length;
- } else {
- dlen = tdPSW & 0x3ff;
- }
- urb->actual_length += dlen;
-
urb->iso_frame_desc[td_list->index].actual_length = dlen;
- if (!(urb->transfer_flags & USB_DISABLE_SPD)
&& (cc == TD_DATAUNDERRUN))
- cc = TD_CC_NOERROR;
-
- urb->iso_frame_desc[td_list->index].status =
cc_to_error[cc];
- }
- } else {
- if (tdBE != 0) {
- if (td_list->hwCBP == 0)
- urb->actual_length = bus_to_virt
(tdBE) - urb->transfer_buffer + 1;
- else
- urb->actual_length = bus_to_virt
(tdCBP) - urb->transfer_buffer;
- }
- }
- }
+ dl_transfer_length(td_list);
+
/* error code of transfer */
cc = TD_CC_GET (tdINFO);
if( cc == TD_CC_STALL) usb_endpoint_halt(urb->dev,
usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
--- usb.org/usb-ohci.h Sun May 14 14:37:57 2000
+++ usb/usb-ohci.h Sat May 20 12:53:50 2000
@@ -432,7 +432,7 @@
static ed_t * ep_add_ed(struct usb_device * usb_dev, unsigned int pipe, int interval,
int load);
static void ep_rm_ed(struct usb_device * usb_dev, ed_t * ed);
/* td */
-static void td_fill(unsigned int info, void * data, int len, urb_t * urb, int type,
int index);
+static void td_fill(unsigned int info, void * data, int len, urb_t * urb, int index);
static void td_submit_urb(urb_t * urb);
/* root hub */
static int rh_submit_urb(urb_t * urb);
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]