[USB] Control transfers now work off OHCI.
authorBalaji Rao <balajirrao@gmail.com>
Mon, 4 Aug 2008 19:55:59 +0000 (01:25 +0530)
committerroot <root@localhost.localdomain>
Mon, 4 Aug 2008 19:55:59 +0000 (01:25 +0530)
src/config.h
src/drivers/bus/usb/ohci.h
src/drivers/bus/usb/ohci_hcd.c

index f43da04..71b2b49 100644 (file)
@@ -17,8 +17,8 @@
  *
  */
 
-#define        CONSOLE_FIRMWARE        /* Default BIOS console */
-#undef CONSOLE_SERIAL          /* Serial port */
+//#define      CONSOLE_FIRMWARE        /* Default BIOS console */
+#define        CONSOLE_SERIAL          /* Serial port */
 #undef CONSOLE_DIRECT_VGA      /* Direct access to VGA card */
 #undef CONSOLE_BTEXT           /* Who knows what this does? */
 #undef CONSOLE_PC_KBD          /* Direct access to PC keyboard */
index 2aabdd6..f990e44 100644 (file)
@@ -182,10 +182,9 @@ struct ohci_td {
 
        /* For driver's use */
        struct list_head        list;
-
        unsigned long           dma;
-
        struct ohci_ed          *ed;
+       unsigned int            len;
 
 } __attribute__ ((aligned(32)));       /* c/b/i need 16; only iso needs 32 */
 
index 8d3632f..8ce315a 100644 (file)
@@ -9,6 +9,7 @@
 
 #include "ohci.h"
 
+int a[1000];
 
 static void ohci_usb_reset (struct ohci_hcd *ohci)
 {
@@ -116,9 +117,32 @@ static struct ohci_td * ohci_alloc_td (struct ohci_hcd *hc, struct ohci_ed *ed)
                td->dma = dma;
                td->ed = ed;
        }
+       
+
        return td;
 }
 
+static inline void ohci_fill_td (struct ohci_hcd *ohci, struct ohci_td *td,
+                               uint32_t info, unsigned long data, unsigned int len)
+{
+       asm("nop");
+       info |= TD_DI_SET(6);
+
+       td->hwINFO = cpu_to_hc32(ohci, info);
+       td->hwCBP = cpu_to_hc32(ohci, data);
+
+       if(data)
+               td->hwBE = cpu_to_hc32(ohci, data + len - 1);
+       else 
+               td->hwBE = 0;
+
+       td->len = len;
+
+       td->ed->hwTailP = cpu_to_hc32(ohci, td->dma);
+       wmb();
+
+}
+
 static void ohci_free_td(struct ohci_td *td)
 {
        free_dma(td, sizeof(*td));
@@ -192,23 +216,6 @@ static void ohci_del_td_from_urbp(struct ohci_td *td)
        list_del(&td->list);
 }
 
-static void ohci_fill_td (struct ohci_hcd *ohci, struct ohci_td *td,
-                               uint32_t info, unsigned long data, unsigned int len)
-{
-       info |= TD_DI_SET(6);
-
-       td->hwINFO = cpu_to_hc32(ohci, info);
-       td->hwCBP = cpu_to_hc32(ohci, data);
-
-       if(data)
-               td->hwBE = cpu_to_hc32(ohci, data + len - 1);
-       else 
-               td->hwBE = 0;
-
-       td->ed->hwTailP = cpu_to_hc32(ohci, td->dma);
-       wmb();
-}
-
 static int ohci_submit_control(struct urb *urb, struct ohci_ed *ed)
 {
        struct ohci_hcd *ohci = hcd_to_ohci(urb->udev->hcd);
@@ -224,7 +231,9 @@ static int ohci_submit_control(struct urb *urb, struct ohci_ed *ed)
 
        info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
        urbp->first_td = td = ed->dummy_td;
+
        ohci_fill_td(ohci, td, info, urb->setup_dma, 8);
+
        ohci_add_td_to_urbp(td, urbp);
        plink = &td->hwNextTD;
 
@@ -283,15 +292,11 @@ static int ohci_submit_control(struct urb *urb, struct ohci_ed *ed)
        wmb();
 
        ed->dummy_td = td;
+       ed->hwTailP = cpu_to_hc32(ohci, td->dma);
        writel(OHCI_CLF, &ohci->regs->cmdstatus); 
 
        wmb();
        
-
-//     while(1) {
-//             DBG("HA HA HA %lx %lx\n", readl(&ohci->regs->fmnumber), ohci->hc_control);
-//             mdelay(1000);
-//     }
        return 0;
 
        ohci_free_td(ed->dummy_td);
@@ -312,6 +317,7 @@ static int ohci_enqueue_urb(struct usb_hcd *hcd, struct urb *urb)
        struct ohci_urb_priv *urbp;
        struct ohci_ed *ed;
        int ret = -ENOMEM;
+       uint32_t info;
 
        ohci = hcd_to_ohci(hcd);                
        urbp = malloc(sizeof(*urbp));
@@ -337,8 +343,8 @@ static int ohci_enqueue_urb(struct usb_hcd *hcd, struct urb *urb)
                                writel(0, &ohci->regs->ed_controlcurrent);
                        }       else {
                                ohci->last_control_ed->hwNextED = cpu_to_hc32(ohci, ed->dma);
-                               ohci->last_control_ed = ed;
                        }
+                       ohci->last_control_ed = ed;
                } else {
                        /* Check to see if this is the first ed */
                        if (!readl(&ohci->regs->ed_bulkhead))
@@ -350,7 +356,14 @@ static int ohci_enqueue_urb(struct usb_hcd *hcd, struct urb *urb)
                }
 
        }
+       
+       /* Update the ed's fa */
        ed = (struct ohci_ed *)urb->ep->hcpriv;
+       info = hc32_to_cpu(ohci, ed->hwINFO);
+       info &= ~((1 << 8) - 1);
+       info |= (urb->udev->devnum);
+       ed->hwINFO = cpu_to_hc32(ohci, info);
+
        /* Add the urbp to the ED's list */
        ohci_add_urbp_to_ed(urbp, ed);
        
@@ -361,6 +374,7 @@ static int ohci_enqueue_urb(struct usb_hcd *hcd, struct urb *urb)
 //             if ((ret = ohci_submit_bulk(urb, ed)) < 0)
 //                     goto err_submit_urb;    
        }
+
        return 0;
 
        return ret;
@@ -371,10 +385,72 @@ err_hcpriv_malloc:
 err_urb_malloc:
        return ret;
 }
+static void ohci_unlink_urb(struct urb *urb __unused)
+{
+}
+
+static int ohci_urb_status(struct urb *urb)
+{
+       int ret = USB_URB_STATUS_COMPLETE;
+       struct ohci_urb_priv *urbp = urb->hcpriv;
+       struct ohci_td *td;
+       struct list_head *p;
+       struct ohci_hcd *ohci = hcd_to_ohci(urb->udev->hcd);
+       uint32_t info;
+
+       /* Check for the status of the first td */
+       info = hc32_to_cpu(ohci, urbp->first_td->hwINFO);
+       if (TD_CC_GET(info) != 0) {
+               if ((info & TD_CC) == TD_CC) {
+                       ret = USB_URB_STATUS_INPROGRESS;
+                       goto out;
+               } else {
+                       ret = USB_URB_STATUS_ERROR;
+                       goto out;
+               }
+       }
+
+       /* Check if URB is complete. Update urb->actual_length */
+       /* Optimie by looking at last_td directly. */
+       td = urbp->last_td;
+       info = hc32_to_cpu(ohci, urbp->last_td->hwINFO);
+       if (TD_CC_GET(info) == 0) {
+               unsigned long be, cbp;
+               be = hc32_to_cpu(ohci, td->hwBE);
+               cbp = hc32_to_cpu(ohci, td->hwCBP);
+
+               if (cbp == be) {
+                               urb->actual_length = urb->transfer_buffer_length;
+                               return USB_URB_STATUS_COMPLETE;
+               }       
+       }
+
+       urb->actual_length = 0;
+       list_for_each(p, &urbp->td_list) {
+               unsigned long cbp, be;
+
+               td = list_entry(p, struct ohci_td, list);
+               info = hc32_to_cpu(ohci, td->hwINFO);
+               cbp = hc32_to_cpu(ohci, td->hwCBP);
+               be = hc32_to_cpu(ohci, td->hwBE);
+
+               if (TD_CC_GET(info) != 0) {
+                       ret = USB_URB_STATUS_INPROGRESS;
+                       goto out;
+               }
+
+               urb->actual_length += td->len - (be - cbp);
+       }
+
+out:
+       return ret;
+}
 
 static struct hc_driver ohci_driver = {
+       .urb_status = ohci_urb_status,
        .enqueue_urb = ohci_enqueue_urb,
        .reset_port = ohci_reset_port,
+       .unlink_urb = ohci_unlink_urb,
 };
 
 static int ohci_start(struct ohci_hcd *ohci)