mirror of
https://github.com/Stichting-MINIX-Research-Foundation/u-boot.git
synced 2025-09-10 12:39:22 -04:00
Fix low-level OHCI transfers for PPC440EP (same as ARM920t and MPC5xxx).
Patch by Stefan Roese, 2 Aug 2005
This commit is contained in:
parent
8a316c9b62
commit
7770ce47e4
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* URB OHCI HCD (Host Controller Driver) for USB on the PPC 440.
|
||||
* URB OHCI HCD (Host Controller Driver) for USB on the PPC440EP.
|
||||
*
|
||||
* (C) Copyright 2003-2004
|
||||
* Gary Jennejohn, DENX Software Engineering <gj@denx.de>
|
||||
@ -43,6 +43,7 @@
|
||||
#include <malloc.h>
|
||||
#include <usb.h>
|
||||
#include "usb_ohci.h"
|
||||
|
||||
#include "usbdev.h"
|
||||
|
||||
#define OHCI_USE_NPS /* force NoPowerSwitching mode */
|
||||
@ -75,7 +76,7 @@
|
||||
#define m16_swap(x) swap_16(x)
|
||||
#define m32_swap(x) swap_32(x)
|
||||
|
||||
#if 1
|
||||
#ifdef CONFIG_440_EP
|
||||
#define ohci_cpu_to_le16(x) (x)
|
||||
#define ohci_cpu_to_le32(x) (x)
|
||||
#else
|
||||
@ -97,6 +98,8 @@ urb_priv_t urb_priv;
|
||||
int got_rhsc;
|
||||
/* device which was disconnected */
|
||||
struct usb_device *devgone;
|
||||
/* flag guarding URB transation */
|
||||
int urb_finished = 0;
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
@ -113,28 +116,20 @@ struct usb_device *devgone;
|
||||
temp; })
|
||||
|
||||
static u32 roothub_a (struct ohci *hc)
|
||||
{
|
||||
return read_roothub(hc, a, 0xfc0fe000);
|
||||
}
|
||||
{ return read_roothub (hc, a, 0xfc0fe000); }
|
||||
static inline u32 roothub_b (struct ohci *hc)
|
||||
{
|
||||
return readl(&hc->regs->roothub.b);
|
||||
}
|
||||
{ return readl (&hc->regs->roothub.b); }
|
||||
static inline u32 roothub_status (struct ohci *hc)
|
||||
{
|
||||
return readl(&hc->regs->roothub.status);
|
||||
}
|
||||
{ return readl (&hc->regs->roothub.status); }
|
||||
static u32 roothub_portstatus (struct ohci *hc, int i)
|
||||
{
|
||||
return read_roothub(hc, portstatus[i], 0xffe0fce0);
|
||||
}
|
||||
{ return read_roothub (hc, portstatus [i], 0xffe0fce0); }
|
||||
|
||||
|
||||
/* forward declaration */
|
||||
static int hc_interrupt (void);
|
||||
static void
|
||||
td_submit_job (struct usb_device * dev, unsigned long pipe, void * buffer,
|
||||
int transfer_len, struct devrequest *setup, urb_priv_t * urb,
|
||||
int interval);
|
||||
int transfer_len, struct devrequest * setup, urb_priv_t * urb, int interval);
|
||||
|
||||
/*-------------------------------------------------------------------------*
|
||||
* URB support functions
|
||||
@ -169,8 +164,7 @@ static int sohci_get_current_frame_number(struct usb_device *dev);
|
||||
* small: 0) header + data packets 1) just header */
|
||||
|
||||
static void pkt_print (struct usb_device * dev, unsigned long pipe, void * buffer,
|
||||
int transfer_len, struct devrequest *setup, char *str,
|
||||
int small)
|
||||
int transfer_len, struct devrequest * setup, char * str, int small)
|
||||
{
|
||||
urb_priv_t * purb = &urb_priv;
|
||||
|
||||
@ -182,7 +176,8 @@ static void pkt_print(struct usb_device *dev, unsigned long pipe, void *buffer,
|
||||
usb_pipeout (pipe)? 'O': 'I',
|
||||
usb_pipetype (pipe) < 2? (usb_pipeint (pipe)? "INTR": "ISOC"):
|
||||
(usb_pipecontrol (pipe)? "CTRL": "BULK"),
|
||||
purb->actual_length, transfer_len, dev->status);
|
||||
purb->actual_length,
|
||||
transfer_len, dev->status);
|
||||
#ifdef OHCI_VERBOSE_DEBUG
|
||||
if (!small) {
|
||||
int i, len;
|
||||
@ -195,7 +190,8 @@ static void pkt_print(struct usb_device *dev, unsigned long pipe, void *buffer,
|
||||
}
|
||||
if (transfer_len > 0 && buffer) {
|
||||
printf (__FILE__ ": data(%d/%d):",
|
||||
purb->actual_length, transfer_len);
|
||||
purb->actual_length,
|
||||
transfer_len);
|
||||
len = usb_pipeout (pipe)?
|
||||
transfer_len: purb->actual_length;
|
||||
for (i = 0; i < 16 && i < len; i++)
|
||||
@ -207,8 +203,7 @@ static void pkt_print(struct usb_device *dev, unsigned long pipe, void *buffer,
|
||||
}
|
||||
|
||||
/* just for debugging; prints non-empty branches of the int ed tree inclusive iso eds*/
|
||||
void ep_print_int_eds(ohci_t * ohci, char *str)
|
||||
{
|
||||
void ep_print_int_eds (ohci_t *ohci, char * str) {
|
||||
int i, j;
|
||||
__u32 * ed_p;
|
||||
for (i= 0; i < 32; i++) {
|
||||
@ -239,7 +234,8 @@ static void ohci_dump_intr_mask(char *label, __u32 mask)
|
||||
(mask & OHCI_INTR_RD) ? " RD" : "",
|
||||
(mask & OHCI_INTR_SF) ? " SF" : "",
|
||||
(mask & OHCI_INTR_WDH) ? " WDH" : "",
|
||||
(mask & OHCI_INTR_SO) ? " SO" : "");
|
||||
(mask & OHCI_INTR_SO) ? " SO" : ""
|
||||
);
|
||||
}
|
||||
|
||||
static void maybe_print_eds (char *label, __u32 value)
|
||||
@ -258,14 +254,10 @@ static void maybe_print_eds(char *label, __u32 value)
|
||||
static char * hcfs2string (int state)
|
||||
{
|
||||
switch (state) {
|
||||
case OHCI_USB_RESET:
|
||||
return "reset";
|
||||
case OHCI_USB_RESUME:
|
||||
return "resume";
|
||||
case OHCI_USB_OPER:
|
||||
return "operational";
|
||||
case OHCI_USB_SUSPEND:
|
||||
return "suspend";
|
||||
case OHCI_USB_RESET: return "reset";
|
||||
case OHCI_USB_RESUME: return "resume";
|
||||
case OHCI_USB_OPER: return "operational";
|
||||
case OHCI_USB_SUSPEND: return "suspend";
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
@ -289,14 +281,18 @@ static void ohci_dump_status(ohci_t * controller)
|
||||
(temp & OHCI_CTRL_BLE) ? " BLE" : "",
|
||||
(temp & OHCI_CTRL_CLE) ? " CLE" : "",
|
||||
(temp & OHCI_CTRL_IE) ? " IE" : "",
|
||||
(temp & OHCI_CTRL_PLE) ? " PLE" : "", temp & OHCI_CTRL_CBSR);
|
||||
(temp & OHCI_CTRL_PLE) ? " PLE" : "",
|
||||
temp & OHCI_CTRL_CBSR
|
||||
);
|
||||
|
||||
temp = readl (®s->cmdstatus);
|
||||
dbg ("cmdstatus: 0x%08x SOC=%d%s%s%s%s", temp,
|
||||
(temp & OHCI_SOC) >> 16,
|
||||
(temp & OHCI_OCR) ? " OCR" : "",
|
||||
(temp & OHCI_BLF) ? " BLF" : "",
|
||||
(temp & OHCI_CLF) ? " CLF" : "", (temp & OHCI_HCR) ? " HCR" : "");
|
||||
(temp & OHCI_CLF) ? " CLF" : "",
|
||||
(temp & OHCI_HCR) ? " HCR" : ""
|
||||
);
|
||||
|
||||
ohci_dump_intr_mask ("intrstatus", readl (®s->intrstatus));
|
||||
ohci_dump_intr_mask ("intrenable", readl (®s->intrenable));
|
||||
@ -326,10 +322,14 @@ static void ohci_dump_roothub(ohci_t * controller, int verbose)
|
||||
(temp & RH_A_OCPM) ? " OCPM" : "",
|
||||
(temp & RH_A_DT) ? " DT" : "",
|
||||
(temp & RH_A_NPS) ? " NPS" : "",
|
||||
(temp & RH_A_PSM) ? " PSM" : "", ndp);
|
||||
(temp & RH_A_PSM) ? " PSM" : "",
|
||||
ndp
|
||||
);
|
||||
temp = roothub_b (controller);
|
||||
dbg ("roothub.b: %08x PPCM=%04x DR=%04x",
|
||||
temp, (temp & RH_B_PPCM) >> 16, (temp & RH_B_DR)
|
||||
temp,
|
||||
(temp & RH_B_PPCM) >> 16,
|
||||
(temp & RH_B_DR)
|
||||
);
|
||||
temp = roothub_status (controller);
|
||||
dbg ("roothub.status: %08x%s%s%s%s%s%s",
|
||||
@ -339,7 +339,8 @@ static void ohci_dump_roothub(ohci_t * controller, int verbose)
|
||||
(temp & RH_HS_LPSC) ? " LPSC" : "",
|
||||
(temp & RH_HS_DRWE) ? " DRWE" : "",
|
||||
(temp & RH_HS_OCI) ? " OCI" : "",
|
||||
(temp & RH_HS_LPS) ? " LPS" : "");
|
||||
(temp & RH_HS_LPS) ? " LPS" : ""
|
||||
);
|
||||
}
|
||||
|
||||
for (i = 0; i < ndp; i++) {
|
||||
@ -352,13 +353,16 @@ static void ohci_dump_roothub(ohci_t * controller, int verbose)
|
||||
(temp & RH_PS_PSSC) ? " PSSC" : "",
|
||||
(temp & RH_PS_PESC) ? " PESC" : "",
|
||||
(temp & RH_PS_CSC) ? " CSC" : "",
|
||||
|
||||
(temp & RH_PS_LSDA) ? " LSDA" : "",
|
||||
(temp & RH_PS_PPS) ? " PPS" : "",
|
||||
(temp & RH_PS_PRS) ? " PRS" : "",
|
||||
(temp & RH_PS_POCI) ? " POCI" : "",
|
||||
(temp & RH_PS_PSS) ? " PSS" : "",
|
||||
|
||||
(temp & RH_PS_PES) ? " PES" : "",
|
||||
(temp & RH_PS_CCS) ? " CCS" : "");
|
||||
(temp & RH_PS_CCS) ? " CCS" : ""
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -374,6 +378,7 @@ static void ohci_dump(ohci_t * controller, int verbose)
|
||||
ohci_dump_roothub (controller, 1);
|
||||
}
|
||||
|
||||
|
||||
#endif /* DEBUG */
|
||||
|
||||
/*-------------------------------------------------------------------------*
|
||||
@ -399,6 +404,16 @@ int sohci_submit_job(struct usb_device *dev, unsigned long pipe, void *buffer,
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* if we have an unfinished URB from previous transaction let's
|
||||
* fail and scream as quickly as possible so as not to corrupt
|
||||
* further communication */
|
||||
if (!urb_finished) {
|
||||
err("sohci_submit_job: URB NOT FINISHED");
|
||||
return -1;
|
||||
}
|
||||
/* we're about to begin a new transaction here so mark the URB unfinished */
|
||||
urb_finished = 0;
|
||||
|
||||
/* every endpoint has a ed, locate and fill it */
|
||||
if (!(ed = ep_add_ed (dev, pipe))) {
|
||||
err("sohci_submit_job: ENOMEM");
|
||||
@ -411,7 +426,8 @@ int sohci_submit_job(struct usb_device *dev, unsigned long pipe, void *buffer,
|
||||
size = (transfer_len - 1) / 4096 + 1;
|
||||
break;
|
||||
case PIPE_CONTROL: /* 1 TD for setup, 1 for ACK and 1 for every 4096 B */
|
||||
size = (transfer_len == 0) ? 2 : (transfer_len - 1) / 4096 + 3;
|
||||
size = (transfer_len == 0)? 2:
|
||||
(transfer_len - 1) / 4096 + 3;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -450,8 +466,7 @@ int sohci_submit_job(struct usb_device *dev, unsigned long pipe, void *buffer,
|
||||
ep_link (ohci, ed);
|
||||
|
||||
/* fill the TDs and link it to the ed */
|
||||
td_submit_job(dev, pipe, buffer, transfer_len, setup, purb_priv,
|
||||
interval);
|
||||
td_submit_job(dev, pipe, buffer, transfer_len, setup, purb_priv, interval);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -487,8 +502,7 @@ static int ep_link(ohci_t * ohci, ed_t * edi)
|
||||
if (ohci->ed_controltail == NULL) {
|
||||
writel (ed, &ohci->regs->ed_controlhead);
|
||||
} else {
|
||||
ohci->ed_controltail->hwNextED =
|
||||
ohci_cpu_to_le32((unsigned long)ed);
|
||||
ohci->ed_controltail->hwNextED = ohci_cpu_to_le32 ((unsigned long)ed);
|
||||
}
|
||||
ed->ed_prev = ohci->ed_controltail;
|
||||
if (!ohci->ed_controltail && !ohci->ed_rm_list[0] &&
|
||||
@ -504,8 +518,7 @@ static int ep_link(ohci_t * ohci, ed_t * edi)
|
||||
if (ohci->ed_bulktail == NULL) {
|
||||
writel (ed, &ohci->regs->ed_bulkhead);
|
||||
} else {
|
||||
ohci->ed_bulktail->hwNextED =
|
||||
ohci_cpu_to_le32((unsigned long)ed);
|
||||
ohci->ed_bulktail->hwNextED = ohci_cpu_to_le32 ((unsigned long)ed);
|
||||
}
|
||||
ed->ed_prev = ohci->ed_bulktail;
|
||||
if (!ohci->ed_bulktail && !ohci->ed_rm_list[0] &&
|
||||
@ -539,17 +552,14 @@ static int ep_unlink(ohci_t * ohci, ed_t * edi)
|
||||
ohci->hc_control &= ~OHCI_CTRL_CLE;
|
||||
writel (ohci->hc_control, &ohci->regs->control);
|
||||
}
|
||||
writel(ohci_cpu_to_le32(*((__u32 *) & ed->hwNextED)),
|
||||
&ohci->regs->ed_controlhead);
|
||||
writel (ohci_cpu_to_le32 (*((__u32 *)&ed->hwNextED)), &ohci->regs->ed_controlhead);
|
||||
} else {
|
||||
ed->ed_prev->hwNextED = ed->hwNextED;
|
||||
}
|
||||
if (ohci->ed_controltail == ed) {
|
||||
ohci->ed_controltail = ed->ed_prev;
|
||||
} else {
|
||||
((ed_t *)
|
||||
ohci_cpu_to_le32(*((__u32 *) & ed->hwNextED)))->
|
||||
ed_prev = ed->ed_prev;
|
||||
((ed_t *)ohci_cpu_to_le32 (*((__u32 *)&ed->hwNextED)))->ed_prev = ed->ed_prev;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -559,17 +569,14 @@ static int ep_unlink(ohci_t * ohci, ed_t * edi)
|
||||
ohci->hc_control &= ~OHCI_CTRL_BLE;
|
||||
writel (ohci->hc_control, &ohci->regs->control);
|
||||
}
|
||||
writel(ohci_cpu_to_le32(*((__u32 *) & ed->hwNextED)),
|
||||
&ohci->regs->ed_bulkhead);
|
||||
writel (ohci_cpu_to_le32 (*((__u32 *)&ed->hwNextED)), &ohci->regs->ed_bulkhead);
|
||||
} else {
|
||||
ed->ed_prev->hwNextED = ed->hwNextED;
|
||||
}
|
||||
if (ohci->ed_bulktail == ed) {
|
||||
ohci->ed_bulktail = ed->ed_prev;
|
||||
} else {
|
||||
((ed_t *)
|
||||
ohci_cpu_to_le32(*((__u32 *) & ed->hwNextED)))->
|
||||
ed_prev = ed->ed_prev;
|
||||
((ed_t *)ohci_cpu_to_le32 (*((__u32 *)&ed->hwNextED)))->ed_prev = ed->ed_prev;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -577,6 +584,7 @@ static int ep_unlink(ohci_t * ohci, ed_t * edi)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* add/reinit an endpoint; this should be done once at the usb_set_configuration command,
|
||||
@ -592,8 +600,7 @@ static ed_t *ep_add_ed(struct usb_device *usb_dev, unsigned long pipe)
|
||||
volatile ed_t *ed;
|
||||
|
||||
ed = ed_ret = &ohci_dev.ed[(usb_pipeendpoint (pipe) << 1) |
|
||||
(usb_pipecontrol(pipe) ? 0 :
|
||||
usb_pipeout(pipe))];
|
||||
(usb_pipecontrol (pipe)? 0: usb_pipeout (pipe))];
|
||||
|
||||
if ((ed->state & ED_DEL) || (ed->state & ED_URB_DEL)) {
|
||||
err("ep_add_ed: pending delete");
|
||||
@ -615,10 +622,9 @@ static ed_t *ep_add_ed(struct usb_device *usb_dev, unsigned long pipe)
|
||||
ed->hwINFO = ohci_cpu_to_le32 (usb_pipedevice (pipe)
|
||||
| usb_pipeendpoint (pipe) << 7
|
||||
| (usb_pipeisoc (pipe)? 0x8000: 0)
|
||||
| (usb_pipecontrol(pipe) ? 0
|
||||
: (usb_pipeout(pipe) ? 0x800 : 0x1000))
|
||||
| usb_pipeslow(pipe) << 13 |
|
||||
usb_maxpacket(usb_dev, pipe) << 16);
|
||||
| (usb_pipecontrol (pipe)? 0: (usb_pipeout (pipe)? 0x800: 0x1000))
|
||||
| usb_pipeslow (pipe) << 13
|
||||
| usb_maxpacket (usb_dev, pipe) << 16);
|
||||
|
||||
return ed_ret;
|
||||
}
|
||||
@ -647,19 +653,16 @@ static void td_fill(ohci_t * ohci, unsigned int info,
|
||||
td_pt->hwNextTD = 0;
|
||||
|
||||
/* fill the old dummy TD */
|
||||
td = urb_priv->td[index] =
|
||||
(td_t *) (ohci_cpu_to_le32(urb_priv->ed->hwTailP) & ~0xf);
|
||||
td = urb_priv->td [index] = (td_t *)(ohci_cpu_to_le32 (urb_priv->ed->hwTailP) & ~0xf);
|
||||
|
||||
td->ed = urb_priv->ed;
|
||||
td->next_dl_td = NULL;
|
||||
td->index = index;
|
||||
td->data = (__u32)data;
|
||||
#ifdef OHCI_FILL_TRACE
|
||||
if ((usb_pipetype(urb_priv->pipe) == PIPE_BULK)
|
||||
&& usb_pipeout(urb_priv->pipe)) {
|
||||
if ((usb_pipetype(urb_priv->pipe) == PIPE_BULK) && usb_pipeout(urb_priv->pipe)) {
|
||||
for (i = 0; i < len; i++)
|
||||
printf("td->data[%d] %#2x ", i,
|
||||
((unsigned char *)td->data)[i]);
|
||||
printf("td->data[%d] %#2x ",i, ((unsigned char *)td->data)[i]);
|
||||
printf("\n");
|
||||
}
|
||||
#endif
|
||||
@ -673,7 +676,6 @@ static void td_fill(ohci_t * ohci, unsigned int info,
|
||||
else
|
||||
td->hwBE = 0;
|
||||
td->hwNextTD = ohci_cpu_to_le32 ((unsigned long)td_pt);
|
||||
td->hwPSW[0] = ohci_cpu_to_le16(((__u32) data & 0x0FFF) | 0xE000);
|
||||
|
||||
/* append to queue */
|
||||
td->ed->hwTailP = td->hwNextTD;
|
||||
@ -682,11 +684,8 @@ static void td_fill(ohci_t * ohci, unsigned int info,
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* prepare all TDs of a transfer */
|
||||
|
||||
static void td_submit_job(struct usb_device *dev, unsigned long pipe,
|
||||
void *buffer, int transfer_len,
|
||||
struct devrequest *setup, urb_priv_t * urb,
|
||||
int interval)
|
||||
static void td_submit_job (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;
|
||||
@ -700,8 +699,7 @@ static void td_submit_job(struct usb_device *dev, unsigned long pipe,
|
||||
toggle = TD_T_TOGGLE;
|
||||
} else {
|
||||
toggle = TD_T_DATA0;
|
||||
usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe),
|
||||
1);
|
||||
usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 1);
|
||||
}
|
||||
urb->td_cnt = 0;
|
||||
if (data_len)
|
||||
@ -711,18 +709,15 @@ static void td_submit_job(struct usb_device *dev, unsigned long pipe,
|
||||
|
||||
switch (usb_pipetype (pipe)) {
|
||||
case PIPE_BULK:
|
||||
info = usb_pipeout(pipe) ? TD_CC | TD_DP_OUT : TD_CC | TD_DP_IN;
|
||||
info = usb_pipeout (pipe)?
|
||||
TD_CC | TD_DP_OUT : TD_CC | TD_DP_IN ;
|
||||
while(data_len > 4096) {
|
||||
td_fill(ohci, info | (cnt ? TD_T_TOGGLE : toggle), data,
|
||||
4096, dev, cnt, urb);
|
||||
data += 4096;
|
||||
data_len -= 4096;
|
||||
cnt++;
|
||||
td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, 4096, dev, cnt, urb);
|
||||
data += 4096; data_len -= 4096; cnt++;
|
||||
}
|
||||
info = usb_pipeout (pipe)?
|
||||
TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ;
|
||||
td_fill(ohci, info | (cnt ? TD_T_TOGGLE : toggle), data,
|
||||
data_len, dev, cnt, urb);
|
||||
td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, data_len, dev, cnt, urb);
|
||||
cnt++;
|
||||
|
||||
if (!ohci->sleeping)
|
||||
@ -734,14 +729,12 @@ static void td_submit_job(struct usb_device *dev, unsigned long pipe,
|
||||
td_fill (ohci, info, setup, 8, dev, cnt++, urb);
|
||||
if (data_len > 0) {
|
||||
info = usb_pipeout (pipe)?
|
||||
TD_CC | TD_R | TD_DP_OUT | TD_T_DATA1 : TD_CC | TD_R
|
||||
| TD_DP_IN | TD_T_DATA1;
|
||||
TD_CC | TD_R | TD_DP_OUT | TD_T_DATA1 : TD_CC | TD_R | TD_DP_IN | TD_T_DATA1;
|
||||
/* NOTE: mishandles transfers >8K, some >4K */
|
||||
td_fill (ohci, info, data, data_len, dev, cnt++, urb);
|
||||
}
|
||||
info = usb_pipeout (pipe)?
|
||||
TD_CC | TD_DP_IN | TD_T_DATA1 : TD_CC | TD_DP_OUT |
|
||||
TD_T_DATA1;
|
||||
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);
|
||||
if (!ohci->sleeping)
|
||||
writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
|
||||
@ -755,6 +748,7 @@ static void td_submit_job(struct usb_device *dev, unsigned long pipe,
|
||||
* Done List handling functions
|
||||
*-------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
/* calculate the transfer length and update the urb */
|
||||
|
||||
static void dl_transfer_length(td_t * td)
|
||||
@ -766,6 +760,7 @@ static void dl_transfer_length(td_t * td)
|
||||
tdBE = ohci_cpu_to_le32 (td->hwBE);
|
||||
tdCBP = ohci_cpu_to_le32 (td->hwCBP);
|
||||
|
||||
|
||||
if (!(usb_pipetype (lurb_priv->pipe) == PIPE_CONTROL &&
|
||||
((td->index == 0) || (td->index == lurb_priv->length - 1)))) {
|
||||
if (tdBE != 0) {
|
||||
@ -798,26 +793,15 @@ static td_t *dl_reverse_done_list(ohci_t * ohci)
|
||||
if (TD_CC_GET (ohci_cpu_to_le32 (td_list->hwINFO))) {
|
||||
lurb_priv = &urb_priv;
|
||||
dbg(" USB-error/status: %x : %p",
|
||||
TD_CC_GET(ohci_cpu_to_le32(td_list->hwINFO)),
|
||||
td_list);
|
||||
TD_CC_GET (ohci_cpu_to_le32 (td_list->hwINFO)), td_list);
|
||||
if (td_list->ed->hwHeadP & ohci_cpu_to_le32 (0x1)) {
|
||||
if (lurb_priv
|
||||
&& ((td_list->index + 1) <
|
||||
lurb_priv->length)) {
|
||||
if (lurb_priv && ((td_list->index + 1) < lurb_priv->length)) {
|
||||
td_list->ed->hwHeadP =
|
||||
(lurb_priv->
|
||||
td[lurb_priv->length -
|
||||
1]->
|
||||
hwNextTD &
|
||||
ohci_cpu_to_le32(0xfffffff0)) |
|
||||
(td_list->ed->
|
||||
hwHeadP & ohci_cpu_to_le32(0x2));
|
||||
lurb_priv->td_cnt +=
|
||||
lurb_priv->length - td_list->index -
|
||||
1;
|
||||
(lurb_priv->td[lurb_priv->length - 1]->hwNextTD & ohci_cpu_to_le32 (0xfffffff0)) |
|
||||
(td_list->ed->hwHeadP & ohci_cpu_to_le32 (0x2));
|
||||
lurb_priv->td_cnt += lurb_priv->length - td_list->index - 1;
|
||||
} else
|
||||
td_list->ed->hwHeadP &=
|
||||
ohci_cpu_to_le32(0xfffffff2);
|
||||
td_list->ed->hwHeadP &= ohci_cpu_to_le32 (0xfffffff2);
|
||||
}
|
||||
#ifdef CONFIG_MPC5200
|
||||
td_list->hwNextTD = 0;
|
||||
@ -839,7 +823,7 @@ static int dl_done_list(ohci_t * ohci, td_t * td_list)
|
||||
td_t *td_list_next = NULL;
|
||||
ed_t *ed;
|
||||
int cc = 0;
|
||||
int stat = 0xff;
|
||||
int stat = 0;
|
||||
/* urb_t *urb; */
|
||||
urb_priv_t *lurb_priv;
|
||||
__u32 tdINFO, edHeadP, edTailP;
|
||||
@ -861,6 +845,7 @@ static int dl_done_list(ohci_t * ohci, td_t * td_list)
|
||||
&& (lurb_priv->state != URB_DEL)) {
|
||||
dbg("ConditionCode %#x", cc);
|
||||
stat = cc_to_error[cc];
|
||||
urb_finished = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -883,7 +868,8 @@ static int dl_done_list(ohci_t * ohci, td_t * td_list)
|
||||
*-------------------------------------------------------------------------*/
|
||||
|
||||
/* Device descriptor */
|
||||
static __u8 root_hub_dev_des[] = {
|
||||
static __u8 root_hub_dev_des[] =
|
||||
{
|
||||
0x12, /* __u8 bLength; */
|
||||
0x01, /* __u8 bDescriptorType; Device */
|
||||
0x10, /* __u16 bcdUSB; v1.1 */
|
||||
@ -904,8 +890,10 @@ static __u8 root_hub_dev_des[] = {
|
||||
0x01 /* __u8 bNumConfigurations; */
|
||||
};
|
||||
|
||||
|
||||
/* Configuration descriptor */
|
||||
static __u8 root_hub_config_des[] = {
|
||||
static __u8 root_hub_config_des[] =
|
||||
{
|
||||
0x09, /* __u8 bLength; */
|
||||
0x02, /* __u8 bDescriptorType; Configuration */
|
||||
0x19, /* __u16 wTotalLength; */
|
||||
@ -938,14 +926,16 @@ static __u8 root_hub_config_des[] = {
|
||||
0xff /* __u8 ep_bInterval; 255 ms */
|
||||
};
|
||||
|
||||
static unsigned char root_hub_str_index0[] = {
|
||||
static unsigned char root_hub_str_index0[] =
|
||||
{
|
||||
0x04, /* __u8 bLength; */
|
||||
0x03, /* __u8 bDescriptorType; String-descriptor */
|
||||
0x09, /* __u8 lang ID */
|
||||
0x04, /* __u8 lang ID */
|
||||
};
|
||||
|
||||
static unsigned char root_hub_str_index1[] = {
|
||||
static unsigned char root_hub_str_index1[] =
|
||||
{
|
||||
28, /* __u8 bLength; */
|
||||
0x03, /* __u8 bDescriptorType; String-descriptor */
|
||||
'O', /* __u8 Unicode */
|
||||
@ -978,6 +968,7 @@ static unsigned char root_hub_str_index1[] = {
|
||||
|
||||
/* Hub class-specific descriptor is constructed dynamically */
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#define OK(x) len = (x); break
|
||||
@ -1005,7 +996,8 @@ int rh_check_port_status(ohci_t * controller)
|
||||
temp = roothub_portstatus (controller, i);
|
||||
/* check for a device disconnect */
|
||||
if (((temp & (RH_PS_PESC | RH_PS_CSC)) ==
|
||||
(RH_PS_PESC | RH_PS_CSC)) && ((temp & RH_PS_CCS) == 0)) {
|
||||
(RH_PS_PESC | RH_PS_CSC)) &&
|
||||
((temp & RH_PS_CCS) == 0)) {
|
||||
res = i;
|
||||
break;
|
||||
}
|
||||
@ -1014,8 +1006,7 @@ int rh_check_port_status(ohci_t * controller)
|
||||
}
|
||||
|
||||
static int ohci_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
|
||||
void *buffer, int transfer_len,
|
||||
struct devrequest *cmd)
|
||||
void *buffer, int transfer_len, struct devrequest *cmd)
|
||||
{
|
||||
void * data = buffer;
|
||||
int leni = transfer_len;
|
||||
@ -1030,8 +1021,7 @@ static int ohci_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
|
||||
|
||||
#ifdef DEBUG
|
||||
urb_priv.actual_length = 0;
|
||||
pkt_print(dev, pipe, buffer, transfer_len, cmd, "SUB(rh)",
|
||||
usb_pipein(pipe));
|
||||
pkt_print(dev, pipe, buffer, transfer_len, cmd, "SUB(rh)", usb_pipein(pipe));
|
||||
#endif
|
||||
if ((pipe & PIPE_INTERRUPT) == PIPE_INTERRUPT) {
|
||||
info("Root-Hub submit IRQ: NOT implemented");
|
||||
@ -1056,26 +1046,21 @@ static int ohci_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
|
||||
*/
|
||||
|
||||
case RH_GET_STATUS:
|
||||
*(__u16 *) data_buf = m16_swap(1);
|
||||
OK(2);
|
||||
*(__u16 *) data_buf = m16_swap (1); OK (2);
|
||||
case RH_GET_STATUS | RH_INTERFACE:
|
||||
*(__u16 *) data_buf = m16_swap(0);
|
||||
OK(2);
|
||||
*(__u16 *) data_buf = m16_swap (0); OK (2);
|
||||
case RH_GET_STATUS | RH_ENDPOINT:
|
||||
*(__u16 *) data_buf = m16_swap(0);
|
||||
OK(2);
|
||||
*(__u16 *) data_buf = m16_swap (0); OK (2);
|
||||
case RH_GET_STATUS | RH_CLASS:
|
||||
*(__u32 *) data_buf =
|
||||
m32_swap(RD_RH_STAT & ~(RH_HS_CRWE | RH_HS_DRWE));
|
||||
*(__u32 *) data_buf = m32_swap (
|
||||
RD_RH_STAT & ~(RH_HS_CRWE | RH_HS_DRWE));
|
||||
OK (4);
|
||||
case RH_GET_STATUS | RH_OTHER | RH_CLASS:
|
||||
*(__u32 *) data_buf = m32_swap(RD_RH_PORTSTAT);
|
||||
OK(4);
|
||||
*(__u32 *) data_buf = m32_swap (RD_RH_PORTSTAT); OK (4);
|
||||
|
||||
case RH_CLEAR_FEATURE | RH_ENDPOINT:
|
||||
switch (wValue) {
|
||||
case (RH_ENDPOINT_STALL):
|
||||
OK(0);
|
||||
case (RH_ENDPOINT_STALL): OK (0);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1084,52 +1069,41 @@ static int ohci_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
|
||||
case RH_C_HUB_LOCAL_POWER:
|
||||
OK(0);
|
||||
case (RH_C_HUB_OVER_CURRENT):
|
||||
WR_RH_STAT(RH_HS_OCIC);
|
||||
OK(0);
|
||||
WR_RH_STAT(RH_HS_OCIC); OK (0);
|
||||
}
|
||||
break;
|
||||
|
||||
case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
|
||||
switch (wValue) {
|
||||
case (RH_PORT_ENABLE):
|
||||
WR_RH_PORTSTAT(RH_PS_CCS);
|
||||
OK(0);
|
||||
WR_RH_PORTSTAT (RH_PS_CCS ); OK (0);
|
||||
case (RH_PORT_SUSPEND):
|
||||
WR_RH_PORTSTAT(RH_PS_POCI);
|
||||
OK(0);
|
||||
WR_RH_PORTSTAT (RH_PS_POCI); OK (0);
|
||||
case (RH_PORT_POWER):
|
||||
WR_RH_PORTSTAT(RH_PS_LSDA);
|
||||
OK(0);
|
||||
WR_RH_PORTSTAT (RH_PS_LSDA); OK (0);
|
||||
case (RH_C_PORT_CONNECTION):
|
||||
WR_RH_PORTSTAT(RH_PS_CSC);
|
||||
OK(0);
|
||||
WR_RH_PORTSTAT (RH_PS_CSC ); OK (0);
|
||||
case (RH_C_PORT_ENABLE):
|
||||
WR_RH_PORTSTAT(RH_PS_PESC);
|
||||
OK(0);
|
||||
WR_RH_PORTSTAT (RH_PS_PESC); OK (0);
|
||||
case (RH_C_PORT_SUSPEND):
|
||||
WR_RH_PORTSTAT(RH_PS_PSSC);
|
||||
OK(0);
|
||||
WR_RH_PORTSTAT (RH_PS_PSSC); OK (0);
|
||||
case (RH_C_PORT_OVER_CURRENT):
|
||||
WR_RH_PORTSTAT(RH_PS_OCIC);
|
||||
OK(0);
|
||||
WR_RH_PORTSTAT (RH_PS_OCIC); OK (0);
|
||||
case (RH_C_PORT_RESET):
|
||||
WR_RH_PORTSTAT(RH_PS_PRSC);
|
||||
OK(0);
|
||||
WR_RH_PORTSTAT (RH_PS_PRSC); OK (0);
|
||||
}
|
||||
break;
|
||||
|
||||
case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
|
||||
switch (wValue) {
|
||||
case (RH_PORT_SUSPEND):
|
||||
WR_RH_PORTSTAT(RH_PS_PSS);
|
||||
OK(0);
|
||||
WR_RH_PORTSTAT (RH_PS_PSS ); OK (0);
|
||||
case (RH_PORT_RESET): /* BUG IN HUP CODE *********/
|
||||
if (RD_RH_PORTSTAT & RH_PS_CCS)
|
||||
WR_RH_PORTSTAT (RH_PS_PRS);
|
||||
OK (0);
|
||||
case (RH_PORT_POWER):
|
||||
WR_RH_PORTSTAT(RH_PS_PPS);
|
||||
OK(0);
|
||||
WR_RH_PORTSTAT (RH_PS_PPS ); OK (0);
|
||||
case (RH_PORT_ENABLE): /* BUG IN HUP CODE *********/
|
||||
if (RD_RH_PORTSTAT & RH_PS_CCS)
|
||||
WR_RH_PORTSTAT (RH_PS_PES );
|
||||
@ -1137,9 +1111,7 @@ static int ohci_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
|
||||
}
|
||||
break;
|
||||
|
||||
case RH_SET_ADDRESS:
|
||||
gohci.rh.devnum = wValue;
|
||||
OK(0);
|
||||
case RH_SET_ADDRESS: gohci.rh.devnum = wValue; OK(0);
|
||||
|
||||
case RH_GET_DESCRIPTOR:
|
||||
switch ((wValue & 0xff00) >> 8) {
|
||||
@ -1147,17 +1119,16 @@ static int ohci_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
|
||||
len = min_t(unsigned int,
|
||||
leni,
|
||||
min_t(unsigned int,
|
||||
sizeof(root_hub_dev_des), wLength));
|
||||
data_buf = root_hub_dev_des;
|
||||
OK(len);
|
||||
sizeof (root_hub_dev_des),
|
||||
wLength));
|
||||
data_buf = root_hub_dev_des; OK(len);
|
||||
case (0x02): /* configuration descriptor */
|
||||
len = min_t(unsigned int,
|
||||
leni,
|
||||
min_t(unsigned int,
|
||||
sizeof (root_hub_config_des),
|
||||
wLength));
|
||||
data_buf = root_hub_config_des;
|
||||
OK(len);
|
||||
data_buf = root_hub_config_des; OK(len);
|
||||
case (0x03): /* string descriptors */
|
||||
if(wValue==0x0300) {
|
||||
len = min_t(unsigned int,
|
||||
@ -1215,13 +1186,9 @@ static int ohci_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
|
||||
OK (len);
|
||||
}
|
||||
|
||||
case RH_GET_CONFIGURATION:
|
||||
*(__u8 *) data_buf = 0x01;
|
||||
OK(1);
|
||||
case RH_GET_CONFIGURATION: *(__u8 *) data_buf = 0x01; OK (1);
|
||||
|
||||
case RH_SET_CONFIGURATION:
|
||||
WR_RH_STAT(0x10000);
|
||||
OK(0);
|
||||
case RH_SET_CONFIGURATION: WR_RH_STAT (0x10000); OK (0);
|
||||
|
||||
default:
|
||||
dbg ("unsupported root hub command");
|
||||
@ -1241,8 +1208,7 @@ static int ohci_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
|
||||
#ifdef DEBUG
|
||||
if (transfer_len)
|
||||
urb_priv.actual_length = transfer_len;
|
||||
pkt_print(dev, pipe, buffer, transfer_len, cmd, "RET(rh)",
|
||||
0 /*usb_pipein(pipe) */ );
|
||||
pkt_print(dev, pipe, buffer, transfer_len, cmd, "RET(rh)", 0/*usb_pipein(pipe)*/);
|
||||
#endif
|
||||
|
||||
return stat;
|
||||
@ -1264,10 +1230,10 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
|
||||
dev->status = USB_ST_CRC_ERR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
urb_priv.actual_length = 0;
|
||||
pkt_print(dev, pipe, buffer, transfer_len, setup, "SUB",
|
||||
usb_pipein(pipe));
|
||||
pkt_print(dev, pipe, buffer, transfer_len, setup, "SUB", usb_pipein(pipe));
|
||||
#endif
|
||||
if (!maxsize) {
|
||||
err("submit_common_message: pipesize for pipe %lx is zero",
|
||||
@ -1275,8 +1241,7 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sohci_submit_job(dev, pipe, buffer, transfer_len, setup, interval) <
|
||||
0) {
|
||||
if (sohci_submit_job(dev, pipe, buffer, transfer_len, setup, interval) < 0) {
|
||||
err("sohci_submit_job failed");
|
||||
return -1;
|
||||
}
|
||||
@ -1296,18 +1261,35 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
|
||||
stat = USB_ST_CRC_ERR;
|
||||
break;
|
||||
}
|
||||
if (stat >= 0 && stat < 0xff) {
|
||||
|
||||
/* NOTE: since we are not interrupt driven in U-Boot and always
|
||||
* handle only one URB at a time, we cannot assume the
|
||||
* transaction finished on the first successful return from
|
||||
* hc_interrupt().. unless the flag for current URB is set,
|
||||
* meaning that all TD's to/from device got actually
|
||||
* transferred and processed. If the current URB is not
|
||||
* finished we need to re-iterate this loop so as
|
||||
* hc_interrupt() gets called again as there needs to be some
|
||||
* more TD's to process still */
|
||||
if ((stat >= 0) && (stat != 0xff) && (urb_finished)) {
|
||||
/* 0xff is returned for an SF-interrupt */
|
||||
break;
|
||||
}
|
||||
|
||||
if (--timeout) {
|
||||
wait_ms(1);
|
||||
if (!urb_finished)
|
||||
dbg("\%");
|
||||
|
||||
} else {
|
||||
err("CTL:TIMEOUT ");
|
||||
dbg("submit_common_msg: TO status %x\n", stat);
|
||||
stat = USB_ST_CRC_ERR;
|
||||
urb_finished = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
/* we got an Root Hub Status Change interrupt */
|
||||
if (got_rhsc) {
|
||||
#ifdef DEBUG
|
||||
@ -1329,13 +1311,13 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
|
||||
devgone = dev;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
dev->status = stat;
|
||||
dev->act_len = transfer_len;
|
||||
|
||||
#ifdef DEBUG
|
||||
pkt_print(dev, pipe, buffer, transfer_len, setup, "RET(ctlr)",
|
||||
usb_pipein(pipe));
|
||||
pkt_print(dev, pipe, buffer, transfer_len, setup, "RET(ctlr)", usb_pipein(pipe));
|
||||
#endif
|
||||
|
||||
/* free TDs in urb_priv */
|
||||
@ -1359,8 +1341,7 @@ int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
|
||||
info("submit_control_msg");
|
||||
#ifdef DEBUG
|
||||
urb_priv.actual_length = 0;
|
||||
pkt_print(dev, pipe, buffer, transfer_len, setup, "SUB",
|
||||
usb_pipein(pipe));
|
||||
pkt_print(dev, pipe, buffer, transfer_len, setup, "SUB", usb_pipein(pipe));
|
||||
#endif
|
||||
if (!maxsize) {
|
||||
err("submit_control_message: pipesize for pipe %lx is zero",
|
||||
@ -1411,7 +1392,8 @@ static int hc_reset(ohci_t * ohci)
|
||||
writel (OHCI_INTR_MIE, &ohci->regs->intrdisable);
|
||||
|
||||
dbg("USB HC reset_hc usb-%s: ctrl = 0x%X ;",
|
||||
ohci->slot_name, readl(&ohci->regs->control));
|
||||
ohci->slot_name,
|
||||
readl (&ohci->regs->control));
|
||||
|
||||
/* Reset USB (needed by some controllers) */
|
||||
ohci->hc_control = 0;
|
||||
@ -1494,24 +1476,34 @@ static int hc_start(ohci_t * ohci)
|
||||
|
||||
/* an interrupt happens */
|
||||
|
||||
static int hc_interrupt(void)
|
||||
static int
|
||||
hc_interrupt (void)
|
||||
{
|
||||
ohci_t *ohci = &gohci;
|
||||
struct ohci_regs *regs = ohci->regs;
|
||||
int ints;
|
||||
int stat = -1;
|
||||
|
||||
if ((ohci->hcca->done_head != 0)
|
||||
&& !(ohci_cpu_to_le32(ohci->hcca->done_head) & 0x01)) {
|
||||
if ((ohci->hcca->done_head != 0) &&
|
||||
!(ohci_cpu_to_le32(ohci->hcca->done_head) & 0x01)) {
|
||||
|
||||
ints = OHCI_INTR_WDH;
|
||||
} else {
|
||||
ints = readl(®s->intrstatus);
|
||||
|
||||
} else if ((ints = readl (®s->intrstatus)) == ~(u32)0) {
|
||||
ohci->disabled++;
|
||||
err ("%s device removed!", ohci->slot_name);
|
||||
return -1;
|
||||
|
||||
} else if ((ints &= readl (®s->intrenable)) == 0) {
|
||||
dbg("hc_interrupt: returning..\n");
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
/* dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca->frame_no)); */
|
||||
|
||||
if (ints & OHCI_INTR_RHSC) {
|
||||
got_rhsc = 1;
|
||||
stat = 0xff;
|
||||
}
|
||||
|
||||
if (ints & OHCI_INTR_UE) {
|
||||
@ -1546,6 +1538,7 @@ static int hc_interrupt(void)
|
||||
/* FIXME: this assumes SOF (1/ms) interrupts don't get lost... */
|
||||
if (ints & OHCI_INTR_SF) {
|
||||
unsigned int frame = ohci_cpu_to_le16 (ohci->hcca->frame_no) & 1;
|
||||
wait_ms(1);
|
||||
writel (OHCI_INTR_SF, ®s->intrdisable);
|
||||
if (ohci->ed_rm_list[frame] != NULL)
|
||||
writel (OHCI_INTR_SF, ®s->intrenable);
|
||||
@ -1579,7 +1572,6 @@ static char ohci_inited = 0;
|
||||
|
||||
int usb_lowlevel_init(void)
|
||||
{
|
||||
|
||||
memset (&gohci, 0, sizeof (ohci_t));
|
||||
memset (&urb_priv, 0, sizeof (urb_priv_t));
|
||||
|
||||
@ -1622,10 +1614,12 @@ int usb_lowlevel_init(void)
|
||||
hc_release_ohci (&gohci);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
ohci_dump (&gohci, 1);
|
||||
#endif
|
||||
ohci_inited = 1;
|
||||
urb_finished = 1;
|
||||
|
||||
/* init the device driver */
|
||||
usb_dev_init();
|
||||
|
Loading…
x
Reference in New Issue
Block a user