📄 usb_ohci.c
字号:
/* replies to the request have to be on a FIFO basis so * we reverse the reversed done-list */static td_t * dl_reverse_done_list (ohci_t *ohci){ __u32 td_list_hc; td_t *td_rev = NULL; td_t *td_list = NULL; urb_priv_t *lurb_priv = NULL; td_list_hc = m32_swap (ohci->hcca->done_head) & 0xfffffff0; ohci->hcca->done_head = 0; while (td_list_hc) { td_list = (td_t *)td_list_hc; if (TD_CC_GET (m32_swap (td_list->hwINFO))) { lurb_priv = td_list->ed->purb; dbg(" USB-error/status: %x : %p", TD_CC_GET (m32_swap (td_list->hwINFO)), td_list); if (td_list->ed->hwHeadP & m32_swap (0x1)) { if (lurb_priv && ((td_list->index + 1) < lurb_priv->length)) { td_list->ed->hwHeadP = (lurb_priv->td[lurb_priv->length - 1]->hwNextTD & m32_swap (0xfffffff0)) | (td_list->ed->hwHeadP & m32_swap (0x2)); lurb_priv->td_cnt += lurb_priv->length - td_list->index - 1; } else td_list->ed->hwHeadP &= m32_swap (0xfffffff2); }#ifdef CONFIG_MPC5200 td_list->hwNextTD = 0;#endif } td_list->next_dl_td = td_rev; td_rev = td_list; td_list_hc = m32_swap (td_list->hwNextTD) & 0xfffffff0; } return td_list;}/*-------------------------------------------------------------------------*//* td done list */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 = 0; /* urb_t *urb; */ urb_priv_t *lurb_priv; __u32 tdINFO, edHeadP, edTailP; while (td_list) { td_list_next = td_list->next_dl_td; tdINFO = m32_swap (td_list->hwINFO); ed = td_list->ed; lurb_priv = ed->purb; dl_transfer_length(td_list); /* error code of transfer */ 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 __u8 root_hub_dev_des[] ={ 0x12, /* __u8 bLength; */ 0x01, /* __u8 bDescriptorType; Device */ 0x10, /* __u16 bcdUSB; v1.1 */ 0x01, 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ 0x00, /* __u8 bDeviceSubClass; */ 0x00, /* __u8 bDeviceProtocol; */ 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ 0x00, /* __u16 idVendor; */ 0x00, 0x00, /* __u16 idProduct; */ 0x00, 0x00, /* __u16 bcdDevice; */ 0x00, 0x00, /* __u8 iManufacturer; */ 0x01, /* __u8 iProduct; */ 0x00, /* __u8 iSerialNumber; */ 0x01 /* __u8 bNumConfigurations; */};/* Configuration descriptor */static __u8 root_hub_config_des[] ={ 0x09, /* __u8 bLength; */ 0x02, /* __u8 bDescriptorType; Configuration */ 0x19, /* __u16 wTotalLength; */ 0x00, 0x01, /* __u8 bNumInterfaces; */ 0x01, /* __u8 bConfigurationValue; */ 0x00, /* __u8 iConfiguration; */ 0x40, /* __u8 bmAttributes; Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */ 0x00, /* __u8 MaxPower; */ /* interface */ 0x09, /* __u8 if_bLength; */ 0x04, /* __u8 if_bDescriptorType; Interface */ 0x00, /* __u8 if_bInterfaceNumber; */ 0x00, /* __u8 if_bAlternateSetting; */ 0x01, /* __u8 if_bNumEndpoints; */ 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */ 0x00, /* __u8 if_bInterfaceSubClass; */ 0x00, /* __u8 if_bInterfaceProtocol; */ 0x00, /* __u8 if_iInterface; */ /* endpoint */ 0x07, /* __u8 ep_bLength; */ 0x05, /* __u8 ep_bDescriptorType; Endpoint */ 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ 0x03, /* __u8 ep_bmAttributes; Interrupt */ 0x02, /* __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */ 0x00, 0xff /* __u8 ep_bInterval; 255 ms */};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[] ={ 28, /* __u8 bLength; */ 0x03, /* __u8 bDescriptorType; String-descriptor */ 'O', /* __u8 Unicode */ 0, /* __u8 Unicode */ 'H', /* __u8 Unicode */ 0, /* __u8 Unicode */ 'C', /* __u8 Unicode */ 0, /* __u8 Unicode */ 'I', /* __u8 Unicode */ 0, /* __u8 Unicode */ ' ', /* __u8 Unicode */ 0, /* __u8 Unicode */ 'R', /* __u8 Unicode */ 0, /* __u8 Unicode */ 'o', /* __u8 Unicode */ 0, /* __u8 Unicode */ 'o', /* __u8 Unicode */ 0, /* __u8 Unicode */ 't', /* __u8 Unicode */ 0, /* __u8 Unicode */ ' ', /* __u8 Unicode */ 0, /* __u8 Unicode */ 'H', /* __u8 Unicode */ 0, /* __u8 Unicode */ 'u', /* __u8 Unicode */ 0, /* __u8 Unicode */ 'b', /* __u8 Unicode */ 0, /* __u8 Unicode */};/* Hub class-specific descriptor is constructed dynamically *//*-------------------------------------------------------------------------*/#define OK(x) len = (x); break#ifdef DEBUG#define WR_RH_STAT(x) {info("WR:status %#8x", (x));writel((x), &gohci.regs->roothub.status);}#define WR_RH_PORTSTAT(x) {info("WR:portstatus[%d] %#8x", wIndex-1, (x));writel((x), &gohci.regs->roothub.portstatus[wIndex-1]);}#else#define WR_RH_STAT(x) writel((x), &gohci.regs->roothub.status)#define WR_RH_PORTSTAT(x) writel((x), &gohci.regs->roothub.portstatus[wIndex-1])#endif#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){ __u32 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; __u32 datab[4]; __u8 *data_buf = (__u8 *)datab; __u16 bmRType_bReq; __u16 wValue; __u16 wIndex; __u16 wLength;#ifdef DEBUGpkt_print(NULL, dev, pipe, buffer, transfer_len, cmd, "SUB(rh)", usb_pipein(pipe));#else wait_ms(1);#endif if ((pipe & PIPE_INTERRUPT) == PIPE_INTERRUPT) { info("Root-Hub submit IRQ: NOT implemented"); return 0; } bmRType_bReq = cmd->requesttype | (cmd->request << 8); wValue = cpu_to_le16 (cmd->value); wIndex = cpu_to_le16 (cmd->index); wLength = cpu_to_le16 (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: *(__u16 *) data_buf = cpu_to_le16 (1); OK (2); case RH_GET_STATUS | RH_INTERFACE: *(__u16 *) data_buf = cpu_to_le16 (0); OK (2); case RH_GET_STATUS | RH_ENDPOINT: *(__u16 *) data_buf = cpu_to_le16 (0); OK (2); case RH_GET_STATUS | RH_CLASS: *(__u32 *) data_buf = cpu_to_le32 ( RD_RH_STAT & ~(RH_HS_CRWE | RH_HS_DRWE)); OK (4); case RH_GET_STATUS | RH_OTHER | RH_CLASS: *(__u32 *) data_buf = cpu_to_le32 (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 ); wait_ms(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(unsigned int, leni, min_t(unsigned int, 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); case (0x03): /* string descriptors */ if(wValue==0x0300) { len = min_t(unsigned int, leni, min_t(unsigned int, sizeof (root_hub_str_index0), wLength)); data_buf = root_hub_str_index0; OK(len); } if(wValue==0x0301) { len = min_t(unsigned int, leni, min_t(unsigned int, 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: { __u32 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(unsigned int, leni, min_t(unsigned int, data_buf [0], wLength)); OK (len); } case RH_GET_CONFIGURATION: *(__u8 *) 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; }#ifdef DEBUG ohci_dump_roothub (&gohci, 1);#else wait_ms(1);#endif len = min_t(int, len, leni); if (data != data_buf) memcpy (data, data_buf, len); dev->act_len = len; dev->status = stat;#ifdef DEBUG pkt_print(NULL, dev, pipe, buffer, transfer_len, cmd, "RET(rh)", 0/*usb_pipein(pipe)*/);#else wait_ms(1);#endif 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)); 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -