📄 usb_ohci.c
字号:
cc = TD_CC_GET (tdINFO);
if (cc != 0) {
dbg("ConditionCode %#x", cc);
stat = cc_to_error[cc];
}
/* see if this done list makes for all TD's of current URB,
* and mark the URB finished if so */
if (++(lurb_priv->td_cnt) == lurb_priv->length) {
#if 1
if ((ed->state & (ED_OPER | ED_UNLINK)) &&
(lurb_priv->state != URB_DEL))
#else
if ((ed->state & (ED_OPER | ED_UNLINK)))
#endif
lurb_priv->finished = sohci_return_job(ohci,
lurb_priv);
else
dbg("dl_done_list: strange.., ED state %x, ed->state\n");
} else
dbg("dl_done_list: processing TD %x, len %x\n", lurb_priv->td_cnt,
lurb_priv->length);
if (ed->state != ED_NEW &&
(usb_pipetype (lurb_priv->pipe) != PIPE_INTERRUPT)) {
edHeadP = m32_swap (ed->hwHeadP) & 0xfffffff0;
edTailP = m32_swap (ed->hwTailP);
/* unlink eds if they are not busy */
if ((edHeadP == edTailP) && (ed->state == ED_OPER))
ep_unlink (ohci, ed);
}
td_list = td_list_next;
}
return stat;
}
/*-------------------------------------------------------------------------*
* Virtual Root Hub
*-------------------------------------------------------------------------*/
/* Device descriptor */
static unsigned char root_hub_dev_des[] =
{
0x12, /* unsigned char bLength; */
0x01, /* unsigned char bDescriptorType; Device */
0x10, /* unsigned short bcdUSB; v1.1 */
0x01,
0x09, /* unsigned char bDeviceClass; HUB_CLASSCODE */
0x00, /* unsigned char bDeviceSubClass; */
0x00, /* unsigned char bDeviceProtocol; */
0x08, /* unsigned char bMaxPacketSize0; 8 Bytes */
0x00, /* unsigned short idVendor; */
0x00,
0x00, /* unsigned short idProduct; */
0x00,
0x00, /* unsigned short bcdDevice; */
0x00,
0x00, /* unsigned char iManufacturer; */
0x01, /* unsigned char iProduct; */
0x00, /* unsigned char iSerialNumber; */
0x01 /* unsigned char bNumConfigurations; */
};
/* Configuration descriptor */
static unsigned char root_hub_config_des[] =
{
0x09, /* unsigned char bLength; */
0x02, /* unsigned char bDescriptorType; Configuration */
0x19, /* unsigned short wTotalLength; */
0x00,
0x01, /* unsigned char bNumInterfaces; */
0x01, /* unsigned char bConfigurationValue; */
0x00, /* unsigned char iConfiguration; */
0x40, /* unsigned char bmAttributes;
Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */
0x00, /* unsigned char MaxPower; */
/* interface */
0x09, /* unsigned char if_bLength; */
0x04, /* unsigned char if_bDescriptorType; Interface */
0x00, /* unsigned char if_bInterfaceNumber; */
0x00, /* unsigned char if_bAlternateSetting; */
0x01, /* unsigned char if_bNumEndpoints; */
0x09, /* unsigned char if_bInterfaceClass; HUB_CLASSCODE */
0x00, /* unsigned char if_bInterfaceSubClass; */
0x00, /* unsigned char if_bInterfaceProtocol; */
0x00, /* unsigned char if_iInterface; */
/* endpoint */
0x07, /* unsigned char ep_bLength; */
0x05, /* unsigned char ep_bDescriptorType; Endpoint */
0x81, /* unsigned char ep_bEndpointAddress; IN Endpoint 1 */
0x03, /* unsigned char ep_bmAttributes; Interrupt */
0x02, /* unsigned short ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */
0x00,
0xff /* unsigned char ep_bInterval; 255 ms */
};
static unsigned char root_hub_str_index0[] =
{
0x04, /* unsigned char bLength; */
0x03, /* unsigned char bDescriptorType; String-descriptor */
0x09, /* unsigned char lang ID */
0x04, /* unsigned char lang ID */
};
static unsigned char root_hub_str_index1[] =
{
28, /* unsigned char bLength; */
0x03, /* unsigned char bDescriptorType; String-descriptor */
'O', /* unsigned char Unicode */
0, /* unsigned char Unicode */
'H', /* unsigned char Unicode */
0, /* unsigned char Unicode */
'C', /* unsigned char Unicode */
0, /* unsigned char Unicode */
'I', /* unsigned char Unicode */
0, /* unsigned char Unicode */
' ', /* unsigned char Unicode */
0, /* unsigned char Unicode */
'R', /* unsigned char Unicode */
0, /* unsigned char Unicode */
'o', /* unsigned char Unicode */
0, /* unsigned char Unicode */
'o', /* unsigned char Unicode */
0, /* unsigned char Unicode */
't', /* unsigned char Unicode */
0, /* unsigned char Unicode */
' ', /* unsigned char Unicode */
0, /* unsigned char Unicode */
'H', /* unsigned char Unicode */
0, /* unsigned char Unicode */
'u', /* unsigned char Unicode */
0, /* unsigned char Unicode */
'b', /* unsigned char Unicode */
0, /* unsigned char Unicode */
};
/* Hub class-specific descriptor is constructed dynamically */
/*-------------------------------------------------------------------------*/
#define OK(x) len = (x); break
#define WR_RH_STAT(x) writel((x), &gohci.regs->roothub.status)
#define WR_RH_PORTSTAT(x) writel((x), &gohci.regs->roothub.portstatus[wIndex-1])
#define RD_RH_STAT roothub_status(&gohci)
#define RD_RH_PORTSTAT roothub_portstatus(&gohci,wIndex-1)
/* request to virtual root hub */
int rh_check_port_status(ohci_t *controller)
{
unsigned int temp, ndp, i;
int res;
res = -1;
temp = roothub_a (controller);
ndp = (temp & RH_A_NDP);
#ifdef CONFIG_AT91C_PQFP_UHPBUG
ndp = (ndp == 2) ? 1:0;
#endif
for (i = 0; i < ndp; i++) {
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)) {
res = i;
break;
}
}
return res;
}
static int ohci_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
void *buffer, int transfer_len, struct devrequest *cmd)
{
void * data = buffer;
int leni = transfer_len;
int len = 0;
int stat = 0;
unsigned int datab[4];
unsigned char *data_buf = (unsigned char *)datab;
unsigned short bmRType_bReq;
unsigned short wValue;
unsigned short wIndex;
unsigned short wLength;
os_dly_waitms(1);
if ((pipe & PIPE_INTERRUPT) == PIPE_INTERRUPT) {
info("Root-Hub submit IRQ: NOT implemented");
return 0;
}
bmRType_bReq = cmd->requesttype | (cmd->request << 8);
wValue = m16_swap (cmd->value);
wIndex = m16_swap (cmd->index);
wLength = m16_swap (cmd->length);
info("Root-Hub: adr: %2x cmd(%1x): %08x %04x %04x %04x",
dev->devnum, 8, bmRType_bReq, wValue, wIndex, wLength);
switch (bmRType_bReq) {
/* Request Destination:
without flags: Device,
RH_INTERFACE: interface,
RH_ENDPOINT: endpoint,
RH_CLASS means HUB here,
RH_OTHER | RH_CLASS almost ever means HUB_PORT here
*/
case RH_GET_STATUS:
*(unsigned short *) data_buf = m16_swap (1); OK (2);
case RH_GET_STATUS | RH_INTERFACE:
*(unsigned short *) data_buf = m16_swap (0); OK (2);
case RH_GET_STATUS | RH_ENDPOINT:
*(unsigned short *) data_buf = m16_swap (0); OK (2);
case RH_GET_STATUS | RH_CLASS:
*(unsigned int *) data_buf = m32_swap (
RD_RH_STAT & ~(RH_HS_CRWE | RH_HS_DRWE));
OK (4);
case RH_GET_STATUS | RH_OTHER | RH_CLASS:
*(unsigned int *) data_buf = m32_swap (RD_RH_PORTSTAT); OK (4);
case RH_CLEAR_FEATURE | RH_ENDPOINT:
switch (wValue) {
case (RH_ENDPOINT_STALL): OK (0);
}
break;
case RH_CLEAR_FEATURE | RH_CLASS:
switch (wValue) {
case RH_C_HUB_LOCAL_POWER:
OK(0);
case (RH_C_HUB_OVER_CURRENT):
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);
case (RH_PORT_SUSPEND):
WR_RH_PORTSTAT (RH_PS_POCI); OK (0);
case (RH_PORT_POWER):
WR_RH_PORTSTAT (RH_PS_LSDA); OK (0);
case (RH_C_PORT_CONNECTION):
WR_RH_PORTSTAT (RH_PS_CSC ); OK (0);
case (RH_C_PORT_ENABLE):
WR_RH_PORTSTAT (RH_PS_PESC); OK (0);
case (RH_C_PORT_SUSPEND):
WR_RH_PORTSTAT (RH_PS_PSSC); OK (0);
case (RH_C_PORT_OVER_CURRENT):
WR_RH_PORTSTAT (RH_PS_OCIC); OK (0);
case (RH_C_PORT_RESET):
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);
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 );
os_dly_waitms(100);
OK (0);
case (RH_PORT_ENABLE): /* BUG IN HUP CODE *********/
if (RD_RH_PORTSTAT & RH_PS_CCS)
WR_RH_PORTSTAT (RH_PS_PES );
OK (0);
}
break;
case RH_SET_ADDRESS: gohci.rh.devnum = wValue; OK(0);
case RH_GET_DESCRIPTOR:
switch ((wValue & 0xff00) >> 8) {
case (0x01): /* device descriptor */
len = min_t( leni, min_t( sizeof (root_hub_dev_des), wLength));
data_buf = root_hub_dev_des; OK(len);
case (0x02): /* configuration descriptor */
len = min_t(leni, min_t(sizeof (root_hub_config_des), wLength));
data_buf = root_hub_config_des; OK(len);
case (0x03): /* string descriptors */
if(wValue==0x0300) {
len = min_t(leni, min_t(sizeof (root_hub_str_index0), wLength));
data_buf = root_hub_str_index0;
OK(len);
}
if(wValue==0x0301) {
len = min_t(leni, min_t(sizeof (root_hub_str_index1), wLength));
data_buf = root_hub_str_index1;
OK(len);
}
default:
stat = USB_ST_STALLED;
}
break;
case RH_GET_DESCRIPTOR | RH_CLASS:
{
unsigned int temp = roothub_a (&gohci);
data_buf [0] = 9; /* min length; */
data_buf [1] = 0x29;
data_buf [2] = temp & RH_A_NDP;
#ifdef CONFIG_AT91C_PQFP_UHPBUG
data_buf [2] = (data_buf [2] == 2) ? 1:0;
#endif
data_buf [3] = 0;
if (temp & RH_A_PSM) /* per-port power switching? */
data_buf [3] |= 0x1;
if (temp & RH_A_NOCP) /* no overcurrent reporting? */
data_buf [3] |= 0x10;
else if (temp & RH_A_OCPM) /* per-port overcurrent reporting? */
data_buf [3] |= 0x8;
/* corresponds to data_buf[4-7] */
datab [1] = 0;
data_buf [5] = (temp & RH_A_POTPGT) >> 24;
temp = roothub_b (&gohci);
data_buf [7] = temp & RH_B_DR;
if (data_buf [2] < 7) {
data_buf [8] = 0xff;
} else {
data_buf [0] += 2;
data_buf [8] = (temp & RH_B_DR) >> 8;
data_buf [10] = data_buf [9] = 0xff;
}
len = min_t(leni, min_t(data_buf [0], wLength));
OK (len);
}
case RH_GET_CONFIGURATION: *(unsigned char *) data_buf = 0x01; OK (1);
case RH_SET_CONFIGURATION: WR_RH_STAT (0x10000); OK (0);
default:
dbg ("unsupported root hub command");
stat = USB_ST_STALLED;
}
os_dly_waitms(1);
len = min_t(len, leni);
if (data != data_buf)
memcpy (data, data_buf, len);
dev->act_len = len;
dev->status = stat;
os_dly_waitms(1);
return stat;
}
/*-------------------------------------------------------------------------*/
/* 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)
{
int stat = 0;
int maxsize = usb_maxpacket(dev, pipe);
int timeout;
urb_priv_t *urb;
urb = malloc(sizeof(urb_priv_t));
if(urb == NULL) return -1;
memset(urb, 0, sizeof(urb_priv_t));
urb->dev = dev;
urb->pipe = pipe;
urb->transfer_buffer = buffer;
urb->transfer_buffer_length = transfer_len;
urb->interval = interval;
/* device pulled? Shortcut the action. */
if (devgone == dev) {
dev->status = USB_ST_CRC_ERR;
urb_free_priv (urb);
return 0;
}
os_dly_waitms(1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -