summaryrefslogtreecommitdiff
path: root/drivers/usb/host/ohci-hcd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host/ohci-hcd.c')
-rw-r--r--drivers/usb/host/ohci-hcd.c327
1 files changed, 231 insertions, 96 deletions
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 97a7ede..494b760 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(&regs->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, &regs->intrdisable);
(void)ohci_readl(&regs->intrdisable); /* flush */
- stat = dl_done_list(&gohci);
+ stat = dl_done_list(ohci);
ohci_writel(OHCI_INTR_WDH, &regs->intrenable);
(void)ohci_readl(&regs->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);
+}