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]

Reply via email to