diff options
author | Tom Rini <trini@konsulko.com> | 2015-05-08 10:46:59 -0400 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2015-05-08 10:46:59 -0400 |
commit | 02ffb580e6ab7aaa7f6703ed35f489e97439cb65 (patch) | |
tree | 77cea28c53d54583a3acfa5534a8aa10054eb29c /drivers/usb/host/ohci-hcd.c | |
parent | 57cc4e64c13bc5f42cb5e8572d2c46e25cf7aea1 (diff) | |
parent | a5e1bcdeebebabdc5d013fbd488f87a4e62ff411 (diff) |
Merge git://git.denx.de/u-boot-dm
Diffstat (limited to 'drivers/usb/host/ohci-hcd.c')
-rw-r--r-- | drivers/usb/host/ohci-hcd.c | 327 |
1 files changed, 231 insertions, 96 deletions
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 97a7edeb53..494b760761 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -103,16 +103,91 @@ static struct pci_device_id ehci_pci_ids[] = { # define m32_swap(x) cpu_to_le32(x) #endif /* CONFIG_SYS_OHCI_BE_CONTROLLER */ +#ifdef CONFIG_DM_USB +/* + * We really should do proper cache flushing everywhere, but for now we only + * do it for new (driver-model) usb code to avoid regressions. + */ +#define flush_dcache_buffer(addr, size) \ + flush_dcache_range((unsigned long)(addr), \ + ALIGN((unsigned long)(addr) + size, ARCH_DMA_MINALIGN)) +#define invalidate_dcache_buffer(addr, size) \ + invalidate_dcache_range((unsigned long)(addr), \ + ALIGN((unsigned long)(addr) + size, ARCH_DMA_MINALIGN)) +#else +#define flush_dcache_buffer(addr, size) +#define invalidate_dcache_buffer(addr, size) +#endif + +/* Do not use sizeof(ed / td) as our ed / td structs contain extra members */ +#define flush_dcache_ed(addr) flush_dcache_buffer(addr, 16) +#define flush_dcache_td(addr) flush_dcache_buffer(addr, 16) +#define flush_dcache_iso_td(addr) flush_dcache_buffer(addr, 32) +#define flush_dcache_hcca(addr) flush_dcache_buffer(addr, 256) +#define invalidate_dcache_ed(addr) invalidate_dcache_buffer(addr, 16) +#define invalidate_dcache_td(addr) invalidate_dcache_buffer(addr, 16) +#define invalidate_dcache_iso_td(addr) invalidate_dcache_buffer(addr, 32) +#define invalidate_dcache_hcca(addr) invalidate_dcache_buffer(addr, 256) + /* global ohci_t */ static ohci_t gohci; /* this must be aligned to a 256 byte boundary */ struct ohci_hcca ghcca[1]; -/* a pointer to the aligned storage */ -struct ohci_hcca *phcca; -/* this allocates EDs for all possible endpoints */ -struct ohci_device ohci_dev; -/* device which was disconnected */ -struct usb_device *devgone; + +/* mapping of the OHCI CC status to error codes */ +static int cc_to_error[16] = { + /* No Error */ 0, + /* CRC Error */ USB_ST_CRC_ERR, + /* Bit Stuff */ USB_ST_BIT_ERR, + /* Data Togg */ USB_ST_CRC_ERR, + /* Stall */ USB_ST_STALLED, + /* DevNotResp */ -1, + /* PIDCheck */ USB_ST_BIT_ERR, + /* UnExpPID */ USB_ST_BIT_ERR, + /* DataOver */ USB_ST_BUF_ERR, + /* DataUnder */ USB_ST_BUF_ERR, + /* reservd */ -1, + /* reservd */ -1, + /* BufferOver */ USB_ST_BUF_ERR, + /* BuffUnder */ USB_ST_BUF_ERR, + /* Not Access */ -1, + /* Not Access */ -1 +}; + +static const char *cc_to_string[16] = { + "No Error", + "CRC: Last data packet from endpoint contained a CRC error.", + "BITSTUFFING: Last data packet from endpoint contained a bit " \ + "stuffing violation", + "DATATOGGLEMISMATCH: Last packet from endpoint had data toggle PID\n" \ + "that did not match the expected value.", + "STALL: TD was moved to the Done Queue because the endpoint returned" \ + " a STALL PID", + "DEVICENOTRESPONDING: Device did not respond to token (IN) or did\n" \ + "not provide a handshake (OUT)", + "PIDCHECKFAILURE: Check bits on PID from endpoint failed on data PID\n"\ + "(IN) or handshake (OUT)", + "UNEXPECTEDPID: Receive PID was not valid when encountered or PID\n" \ + "value is not defined.", + "DATAOVERRUN: The amount of data returned by the endpoint exceeded\n" \ + "either the size of the maximum data packet allowed\n" \ + "from the endpoint (found in MaximumPacketSize field\n" \ + "of ED) or the remaining buffer size.", + "DATAUNDERRUN: The endpoint returned less than MaximumPacketSize\n" \ + "and that amount was not sufficient to fill the\n" \ + "specified buffer", + "reserved1", + "reserved2", + "BUFFEROVERRUN: During an IN, HC received data from endpoint faster\n" \ + "than it could be written to system memory", + "BUFFERUNDERRUN: During an OUT, HC could not retrieve data from\n" \ + "system memory fast enough to keep up with data USB " \ + "data rate.", + "NOT ACCESSED: This code is set by software before the TD is placed" \ + "on a list to be processed by the HC.(1)", + "NOT ACCESSED: This code is set by software before the TD is placed" \ + "on a list to be processed by the HC.(2)", +}; static inline u32 roothub_a(struct ohci *hc) { return ohci_readl(&hc->regs->roothub.a); } @@ -124,11 +199,42 @@ static inline u32 roothub_portstatus(struct ohci *hc, int i) { return ohci_readl(&hc->regs->roothub.portstatus[i]); } /* forward declaration */ -static int hc_interrupt(void); -static void td_submit_job(struct usb_device *dev, unsigned long pipe, - void *buffer, int transfer_len, +static int hc_interrupt(ohci_t *ohci); +static void td_submit_job(ohci_t *ohci, struct usb_device *dev, + unsigned long pipe, void *buffer, int transfer_len, struct devrequest *setup, urb_priv_t *urb, int interval); +static int ep_link(ohci_t * ohci, ed_t * ed); +static int ep_unlink(ohci_t * ohci, ed_t * ed); +static ed_t *ep_add_ed(ohci_dev_t *ohci_dev, struct usb_device *usb_dev, + unsigned long pipe, int interval, int load); + +/*-------------------------------------------------------------------------*/ + +/* TDs ... */ +static struct td *td_alloc(ohci_dev_t *ohci_dev, struct usb_device *usb_dev) +{ + int i; + struct td *td; + + td = NULL; + for (i = 0; i < NUM_TD; i++) + { + if (ohci_dev->tds[i].usb_dev == NULL) + { + td = &ohci_dev->tds[i]; + td->usb_dev = usb_dev; + break; + } + } + + return td; +} + +static inline void ed_free(struct ed *ed) +{ + ed->usb_dev = NULL; +} /*-------------------------------------------------------------------------* * URB support functions @@ -158,18 +264,18 @@ static void urb_free_priv(urb_priv_t *urb) /*-------------------------------------------------------------------------*/ #ifdef DEBUG -static int sohci_get_current_frame_number(struct usb_device *dev); +static int sohci_get_current_frame_number(ohci_t *ohci); /* debug| print the main components of an URB * small: 0) header + data packets 1) just header */ -static void pkt_print(urb_priv_t *purb, struct usb_device *dev, +static void pkt_print(ohci_t *ohci, urb_priv_t *purb, struct usb_device *dev, unsigned long pipe, void *buffer, int transfer_len, struct devrequest *setup, char *str, int small) { dbg("%s URB:[%4x] dev:%2lu,ep:%2lu-%c,type:%s,len:%d/%d stat:%#lx", str, - sohci_get_current_frame_number(dev), + sohci_get_current_frame_number(ohci), usb_pipedevice(pipe), usb_pipeendpoint(pipe), usb_pipeout(pipe)? 'O': 'I', @@ -213,9 +319,11 @@ void ep_print_int_eds(ohci_t *ohci, char *str) ed_p = &(ohci->hcca->int_table [i]); if (*ed_p == 0) continue; + invalidate_dcache_ed(ed_p); printf(__FILE__ ": %s branch int %2d(%2x):", str, i, i); while (*ed_p != 0 && j--) { ed_t *ed = (ed_t *)m32_swap(ed_p); + invalidate_dcache_ed(ed); printf(" ed: %4x;", ed->hwINFO); ed_p = &ed->hwNextED; } @@ -246,6 +354,7 @@ static void maybe_print_eds(char *label, __u32 value) if (value) { dbg("%s %08x", label, value); + invalidate_dcache_ed(edp); dbg("%08x", edp->hwINFO); dbg("%08x", edp->hwTailP); dbg("%08x", edp->hwHeadP); @@ -380,6 +489,7 @@ static void ohci_dump(ohci_t *controller, int verbose) ohci_dump_status(controller); if (verbose) ep_print_int_eds(controller, "hcca"); + invalidate_dcache_hcca(controller->hcca); dbg("hcca frame #%04x", controller->hcca->frame_no); ohci_dump_roothub(controller, 1); } @@ -391,9 +501,9 @@ static void ohci_dump(ohci_t *controller, int verbose) /* get a transfer request */ -int sohci_submit_job(urb_priv_t *urb, struct devrequest *setup) +int sohci_submit_job(ohci_t *ohci, ohci_dev_t *ohci_dev, urb_priv_t *urb, + struct devrequest *setup) { - ohci_t *ohci; ed_t *ed; urb_priv_t *purb_priv = urb; int i, size = 0; @@ -403,8 +513,6 @@ int sohci_submit_job(urb_priv_t *urb, struct devrequest *setup) int transfer_len = urb->transfer_buffer_length; int interval = urb->interval; - ohci = &gohci; - /* when controller's hung, permit only roothub cleanup attempts * such as powering down ports */ if (ohci->disabled) { @@ -417,7 +525,7 @@ int sohci_submit_job(urb_priv_t *urb, struct devrequest *setup) urb->finished = 0; /* every endpoint has a ed, locate and fill it */ - ed = ep_add_ed(dev, pipe, interval, 1); + ed = ep_add_ed(ohci_dev, dev, pipe, interval, 1); if (!ed) { err("sohci_submit_job: ENOMEM"); return -1; @@ -453,7 +561,7 @@ int sohci_submit_job(urb_priv_t *urb, struct devrequest *setup) /* allocate the TDs */ /* note that td[0] was allocated in ep_add_ed */ for (i = 0; i < size; i++) { - purb_priv->td[i] = td_alloc(dev); + purb_priv->td[i] = td_alloc(ohci_dev, dev); if (!purb_priv->td[i]) { purb_priv->length = i; urb_free_priv(purb_priv); @@ -473,7 +581,7 @@ int sohci_submit_job(urb_priv_t *urb, struct devrequest *setup) ep_link(ohci, ed); /* fill the TDs and link it to the ed */ - td_submit_job(dev, pipe, buffer, transfer_len, + td_submit_job(ohci, dev, pipe, buffer, transfer_len, setup, purb_priv, interval); return 0; @@ -495,7 +603,7 @@ static inline int sohci_return_job(struct ohci *hc, urb_priv_t *urb) ohci_readl(®s->intrdisable); /* PCI posting flush */ } urb->actual_length = 0; - td_submit_job( + td_submit_job( hc, urb->dev, urb->pipe, urb->transfer_buffer, @@ -517,11 +625,9 @@ static inline int sohci_return_job(struct ohci *hc, urb_priv_t *urb) #ifdef DEBUG /* tell us the current USB frame number */ - -static int sohci_get_current_frame_number(struct usb_device *usb_dev) +static int sohci_get_current_frame_number(ohci_t *ohci) { - ohci_t *ohci = &gohci; - + invalidate_dcache_hcca(ohci->hcca); return m16_swap(ohci->hcca->frame_no); } #endif @@ -600,6 +706,7 @@ static int ep_link(ohci_t *ohci, ed_t *edi) switch (ed->type) { case PIPE_CONTROL: ed->hwNextED = 0; + flush_dcache_ed(ed); if (ohci->ed_controltail == NULL) ohci_writel(ed, &ohci->regs->ed_controlhead); else @@ -617,6 +724,7 @@ static int ep_link(ohci_t *ohci, ed_t *edi) case PIPE_BULK: ed->hwNextED = 0; + flush_dcache_ed(ed); if (ohci->ed_bulktail == NULL) ohci_writel(ed, &ohci->regs->ed_bulkhead); else @@ -649,7 +757,9 @@ static int ep_link(ohci_t *ohci, ed_t *edi) inter = ep_rev(6, ((ed_t *)ed_p)->int_interval); ed->hwNextED = *ed_p; + flush_dcache_ed(ed); *ed_p = m32_swap((unsigned long)ed); + flush_dcache_hcca(ohci->hcca); } break; } @@ -662,6 +772,8 @@ static int ep_link(ohci_t *ohci, ed_t *edi) static void periodic_unlink(struct ohci *ohci, volatile struct ed *ed, unsigned index, unsigned period) { + __maybe_unused unsigned long aligned_ed_p; + for (; index < NUM_INTS; index += period) { __u32 *ed_p = &ohci->hcca->int_table [index]; @@ -670,6 +782,12 @@ static void periodic_unlink(struct ohci *ohci, volatile struct ed *ed, if (((struct ed *) m32_swap((unsigned long)ed_p)) == ed) { *ed_p = ed->hwNextED; +#ifdef CONFIG_DM_USB + aligned_ed_p = (unsigned long)ed_p; + aligned_ed_p &= ~(ARCH_DMA_MINALIGN - 1); + flush_dcache_range(aligned_ed_p, + aligned_ed_p + ARCH_DMA_MINALIGN); +#endif break; } ed_p = &(((struct ed *) @@ -689,6 +807,7 @@ static int ep_unlink(ohci_t *ohci, ed_t *edi) int i; ed->hwINFO |= m32_swap(OHCI_ED_SKIP); + flush_dcache_ed(ed); switch (ed->type) { case PIPE_CONTROL: @@ -702,6 +821,7 @@ static int ep_unlink(ohci_t *ohci, ed_t *edi) &ohci->regs->ed_controlhead); } else { ed->ed_prev->hwNextED = ed->hwNextED; + flush_dcache_ed(ed->ed_prev); } if (ohci->ed_controltail == ed) { ohci->ed_controltail = ed->ed_prev; @@ -722,6 +842,7 @@ static int ep_unlink(ohci_t *ohci, ed_t *edi) &ohci->regs->ed_bulkhead); } else { ed->ed_prev->hwNextED = ed->hwNextED; + flush_dcache_ed(ed->ed_prev); } if (ohci->ed_bulktail == ed) { ohci->ed_bulktail = ed->ed_prev; @@ -751,14 +872,14 @@ static int ep_unlink(ohci_t *ohci, ed_t *edi) * info fields are setted anyway even though most of them should not * change */ -static ed_t *ep_add_ed(struct usb_device *usb_dev, unsigned long pipe, - int interval, int load) +static ed_t *ep_add_ed(ohci_dev_t *ohci_dev, struct usb_device *usb_dev, + unsigned long pipe, int interval, int load) { td_t *td; ed_t *ed_ret; volatile ed_t *ed; - ed = ed_ret = &ohci_dev.ed[(usb_pipeendpoint(pipe) << 1) | + ed = ed_ret = &ohci_dev->ed[(usb_pipeendpoint(pipe) << 1) | (usb_pipecontrol(pipe)? 0: usb_pipeout(pipe))]; if ((ed->state & ED_DEL) || (ed->state & ED_URB_DEL)) { @@ -769,12 +890,12 @@ static ed_t *ep_add_ed(struct usb_device *usb_dev, unsigned long pipe, if (ed->state == ED_NEW) { /* dummy td; end of td list for ed */ - td = td_alloc(usb_dev); + td = td_alloc(ohci_dev, usb_dev); ed->hwTailP = m32_swap((unsigned long)td); ed->hwHeadP = ed->hwTailP; ed->state = ED_UNLINK; ed->type = usb_pipetype(pipe); - ohci_dev.ed_cnt++; + ohci_dev->ed_cnt++; } ed->hwINFO = m32_swap(usb_pipedevice(pipe) @@ -790,6 +911,8 @@ static ed_t *ep_add_ed(struct usb_device *usb_dev, unsigned long pipe, ed->int_load = load; } + flush_dcache_ed(ed); + return ed_ret; } @@ -815,6 +938,7 @@ static void td_fill(ohci_t *ohci, unsigned int info, /* use this td as the next dummy */ td_pt = urb_priv->td [index]; td_pt->hwNextTD = 0; + flush_dcache_td(td_pt); /* fill the old dummy TD */ td = urb_priv->td [index] = @@ -842,27 +966,30 @@ static void td_fill(ohci_t *ohci, unsigned int info, td->hwBE = 0; td->hwNextTD = m32_swap((unsigned long)td_pt); + flush_dcache_td(td); /* append to queue */ td->ed->hwTailP = td->hwNextTD; + flush_dcache_ed(td->ed); } /*-------------------------------------------------------------------------*/ /* prepare all TDs of a transfer */ -static void td_submit_job(struct usb_device *dev, unsigned long pipe, - void *buffer, int transfer_len, +static void td_submit_job(ohci_t *ohci, struct usb_device *dev, + unsigned long pipe, void *buffer, int transfer_len, struct devrequest *setup, urb_priv_t *urb, int interval) { - ohci_t *ohci = &gohci; int data_len = transfer_len; void *data; int cnt = 0; __u32 info = 0; unsigned int toggle = 0; + flush_dcache_buffer(buffer, data_len); + /* OHCI handles the DATA-toggles itself, we just use the USB-toggle * bits for reseting */ if (usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe))) { @@ -902,6 +1029,7 @@ static void td_submit_job(struct usb_device *dev, unsigned long pipe, case PIPE_CONTROL: /* Setup phase */ info = TD_CC | TD_DP_SETUP | TD_T_DATA0; + flush_dcache_buffer(setup, 8); td_fill(ohci, info, setup, 8, dev, cnt++, urb); /* Optional Data phase */ @@ -914,7 +1042,7 @@ static void td_submit_job(struct usb_device *dev, unsigned long pipe, } /* Status phase */ - info = usb_pipeout(pipe)? + info = (usb_pipeout(pipe) || data_len == 0) ? TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT | TD_T_DATA1; td_fill(ohci, info, data, 0, dev, cnt++, urb); @@ -973,6 +1101,7 @@ static void check_status(td_t *td_list) if (cc) { err(" USB-error: %s (%x)", cc_to_string[cc], cc); + invalidate_dcache_ed(td_list->ed); if (*phwHeadP & m32_swap(0x1)) { if (lurb_priv && ((td_list->index + 1) < urb_len)) { @@ -985,9 +1114,11 @@ static void check_status(td_t *td_list) td_list->index - 1; } else *phwHeadP &= m32_swap(0xfffffff2); + flush_dcache_ed(td_list->ed); } #ifdef CONFIG_MPC5200 td_list->hwNextTD = 0; + flush_dcache_td(td_list); #endif } } @@ -1000,11 +1131,14 @@ static td_t *dl_reverse_done_list(ohci_t *ohci) td_t *td_rev = NULL; td_t *td_list = NULL; + invalidate_dcache_hcca(ohci->hcca); td_list_hc = m32_swap(ohci->hcca->done_head) & 0xfffffff0; ohci->hcca->done_head = 0; + flush_dcache_hcca(ohci->hcca); while (td_list_hc) { td_list = (td_t *)td_list_hc; + invalidate_dcache_td(td_list); check_status(td_list); td_list->next_dl_td = td_rev; td_rev = td_list; @@ -1039,6 +1173,7 @@ static int takeback_td(ohci_t *ohci, td_t *td_list) urb_priv_t *lurb_priv; __u32 tdINFO, edHeadP, edTailP; + invalidate_dcache_td(td_list); tdINFO = m32_swap(td_list->hwINFO); ed = td_list->ed; @@ -1064,6 +1199,7 @@ static int takeback_td(ohci_t *ohci, td_t *td_list) lurb_priv->td_cnt, lurb_priv->length); if (ed->state != ED_NEW && (!usb_pipeint(lurb_priv->pipe))) { + invalidate_dcache_ed(ed); edHeadP = m32_swap(ed->hwHeadP) & 0xfffffff0; edTailP = m32_swap(ed->hwTailP); @@ -1100,16 +1236,16 @@ static int dl_done_list(ohci_t *ohci) #define OK(x) len = (x); break #ifdef DEBUG #define WR_RH_STAT(x) {info("WR:status %#8x", (x)); ohci_writel((x), \ - &gohci.regs->roothub.status); } + &ohci->regs->roothub.status); } #define WR_RH_PORTSTAT(x) {info("WR:portstatus[%d] %#8x", wIndex-1, \ - (x)); ohci_writel((x), &gohci.regs->roothub.portstatus[wIndex-1]); } + (x)); ohci_writel((x), &ohci->regs->roothub.portstatus[wIndex-1]); } #else -#define WR_RH_STAT(x) ohci_writel((x), &gohci.regs->roothub.status) +#define WR_RH_STAT(x) ohci_writel((x), &ohci->regs->roothub.status) #define WR_RH_PORTSTAT(x) ohci_writel((x), \ - &gohci.regs->roothub.portstatus[wIndex-1]) + &ohci->regs->roothub.portstatus[wIndex-1]) #endif -#define RD_RH_STAT roothub_status(&gohci) -#define RD_RH_PORTSTAT roothub_portstatus(&gohci, wIndex-1) +#define RD_RH_STAT roothub_status(ohci) +#define RD_RH_PORTSTAT roothub_portstatus(ohci, wIndex-1) /* request to virtual root hub */ @@ -1137,8 +1273,9 @@ int rh_check_port_status(ohci_t *controller) return res; } -static int ohci_submit_rh_msg(struct usb_device *dev, unsigned long pipe, - void *buffer, int transfer_len, struct devrequest *cmd) +static int ohci_submit_rh_msg(ohci_t *ohci, struct usb_device *dev, + unsigned long pipe, void *buffer, int transfer_len, + struct devrequest *cmd) { void *data = buffer; int leni = transfer_len; @@ -1151,7 +1288,7 @@ static int ohci_submit_rh_msg(struct usb_device *dev, unsigned long pipe, ALLOC_ALIGN_BUFFER(__u8, databuf, 16, sizeof(u32)); #ifdef DEBUG -pkt_print(NULL, dev, pipe, buffer, transfer_len, +pkt_print(ohci, NULL, dev, pipe, buffer, transfer_len, cmd, "SUB(rh)", usb_pipein(pipe)); #else mdelay(1); @@ -1245,7 +1382,7 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len, break; case RH_SET_ADDRESS: - gohci.rh.devnum = wValue; + ohci->rh.devnum = wValue; OK(0); case RH_GET_DESCRIPTOR: @@ -1290,7 +1427,7 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len, case RH_GET_DESCRIPTOR | RH_CLASS: { - __u32 temp = roothub_a(&gohci); + __u32 temp = roothub_a(ohci); databuf[0] = 9; /* min length; */ databuf[1] = 0x29; @@ -1309,7 +1446,7 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len, databuf[4] = 0; databuf[5] = (temp & RH_A_POTPGT) >> 24; databuf[6] = 0; - temp = roothub_b(&gohci); + temp = roothub_b(ohci); databuf[7] = temp & RH_B_DR; if (databuf[2] < 7) { databuf[8] = 0xff; @@ -1338,7 +1475,7 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len, } #ifdef DEBUG - ohci_dump_roothub(&gohci, 1); + ohci_dump_roothub(ohci, 1); #else mdelay(1); #endif @@ -1350,7 +1487,7 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len, dev->status = stat; #ifdef DEBUG - pkt_print(NULL, dev, pipe, buffer, + pkt_print(ohci, NULL, dev, pipe, buffer, transfer_len, cmd, "RET(rh)", 0/*usb_pipein(pipe)*/); #else mdelay(1); @@ -1363,8 +1500,9 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len, /* common code for handling submit messages - used for all but root hub */ /* accesses. */ -int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer, - int transfer_len, struct devrequest *setup, int interval) +static int submit_common_msg(ohci_t *ohci, struct usb_device *dev, + unsigned long pipe, void *buffer, int transfer_len, + struct devrequest *setup, int interval) { int stat = 0; int maxsize = usb_maxpacket(dev, pipe); @@ -1380,15 +1518,9 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer, urb->transfer_buffer_length = transfer_len; urb->interval = interval; - /* device pulled? Shortcut the action. */ - if (devgone == dev) { - dev->status = USB_ST_CRC_ERR; - return 0; - } - #ifdef DEBUG urb->actual_length = 0; - pkt_print(urb, dev, pipe, buffer, transfer_len, + pkt_print(ohci, urb, dev, pipe, buffer, transfer_len, setup, "SUB", usb_pipein(pipe)); #else mdelay(1); @@ -1399,14 +1531,14 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer, return -1; } - if (sohci_submit_job(urb, setup) < 0) { + if (sohci_submit_job(ohci, &ohci->ohci_dev, urb, setup) < 0) { err("sohci_submit_job failed"); return -1; } #if 0 mdelay(10); - /* ohci_dump_status(&gohci); */ + /* ohci_dump_status(ohci); */ #endif timeout = USB_TIMEOUT_MS(pipe); @@ -1414,7 +1546,7 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer, /* wait for it to complete */ for (;;) { /* check whether the controller is done */ - stat = hc_interrupt(); + stat = hc_interrupt(ohci); if (stat < 0) { stat = USB_ST_CRC_ERR; break; @@ -1440,7 +1572,8 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer, dbg("*"); } else { - err("CTL:TIMEOUT "); + if (!usb_pipeint(pipe)) + err("CTL:TIMEOUT "); dbg("submit_common_msg: TO status %x\n", stat); urb->finished = 1; stat = USB_ST_CRC_ERR; @@ -1451,8 +1584,11 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer, dev->status = stat; dev->act_len = urb->actual_length; + if (usb_pipein(pipe) && dev->status == 0 && dev->act_len) + invalidate_dcache_buffer(buffer, dev->act_len); + #ifdef DEBUG - pkt_print(urb, dev, pipe, buffer, transfer_len, + pkt_print(ohci, urb, dev, pipe, buffer, transfer_len, setup, "RET(ctlr)", usb_pipein(pipe)); #else mdelay(1); @@ -1469,17 +1605,27 @@ int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer, int transfer_len) { info("submit_bulk_msg"); - return submit_common_msg(dev, pipe, buffer, transfer_len, NULL, 0); + return submit_common_msg(&gohci, dev, pipe, buffer, transfer_len, + NULL, 0); } -int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, - int transfer_len, struct devrequest *setup) +int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer, + int transfer_len, int interval) +{ + info("submit_int_msg"); + return submit_common_msg(&gohci, dev, pipe, buffer, transfer_len, NULL, + interval); +} + +static int _ohci_submit_control_msg(ohci_t *ohci, struct usb_device *dev, + unsigned long pipe, void *buffer, int transfer_len, + struct devrequest *setup) { int maxsize = usb_maxpacket(dev, pipe); info("submit_control_msg"); #ifdef DEBUG - pkt_print(NULL, dev, pipe, buffer, transfer_len, + pkt_print(ohci, NULL, dev, pipe, buffer, transfer_len, setup, "SUB", usb_pipein(pipe)); #else mdelay(1); @@ -1489,22 +1635,15 @@ int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, pipe); return -1; } - if (((pipe >> 8) & 0x7f) == gohci.rh.devnum) { - gohci.rh.dev = dev; + if (((pipe >> 8) & 0x7f) == ohci->rh.devnum) { + ohci->rh.dev = dev; /* root hub - redirect */ - return ohci_submit_rh_msg(dev, pipe, buffer, transfer_len, - setup); + return ohci_submit_rh_msg(ohci, dev, pipe, buffer, + transfer_len, setup); } - return submit_common_msg(dev, pipe, buffer, transfer_len, setup, 0); -} - -int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer, - int transfer_len, int interval) -{ - info("submit_int_msg"); - return submit_common_msg(dev, pipe, buffer, transfer_len, NULL, - interval); + return submit_common_msg(ohci, dev, pipe, buffer, transfer_len, + setup, 0); } /*-------------------------------------------------------------------------* @@ -1648,13 +1787,14 @@ static int hc_start(ohci_t *ohci) /* an interrupt happens */ -static int hc_interrupt(void) +static int hc_interrupt(ohci_t *ohci) { - ohci_t *ohci = &gohci; struct ohci_regs *regs = ohci->regs; int ints; int stat = -1; + invalidate_dcache_hcca(ohci->hcca); + if ((ohci->hcca->done_head != 0) && !(m32_swap(ohci->hcca->done_head) & 0x01)) { ints = OHCI_INTR_WDH; @@ -1702,7 +1842,7 @@ static int hc_interrupt(void) mdelay(1); ohci_writel(OHCI_INTR_WDH, ®s->intrdisable); (void)ohci_readl(®s->intrdisable); /* flush */ - stat = dl_done_list(&gohci); + stat = dl_done_list(ohci); ohci_writel(OHCI_INTR_WDH, ®s->intrenable); (void)ohci_readl(®s->intrdisable); /* flush */ } @@ -1772,21 +1912,9 @@ int usb_lowlevel_init(int index, enum usb_init_type init, void **controller) err("HCCA not aligned!!"); return -1; } - phcca = &ghcca[0]; - info("aligned ghcca %p", phcca); - memset(&ohci_dev, 0, sizeof(struct ohci_device)); - if ((__u32)&ohci_dev.ed[0] & 0x7) { - err("EDs not aligned!!"); - return -1; - } - memset(gtd, 0, sizeof(td_t) * (NUM_TD + 1)); - if ((__u32)gtd & 0x7) { - err("TDs not aligned!!"); - return -1; - } - ptd = gtd; - gohci.hcca = phcca; - memset(phcca, 0, sizeof(struct ohci_hcca)); + gohci.hcca = &ghcca[0]; + info("aligned ghcca %p", gohci.hcca); + memset(gohci.hcca, 0, sizeof(struct ohci_hcca)); gohci.disabled = 1; gohci.sleeping = 0; @@ -1880,3 +2008,10 @@ int usb_lowlevel_stop(int index) ohci_inited = 0; return 0; } + +int submit_control_msg(struct usb_device *dev, unsigned long pipe, + void *buffer, int transfer_len, struct devrequest *setup) +{ + return _ohci_submit_control_msg(&gohci, dev, pipe, buffer, + transfer_len, setup); +} |