📄 usb_ohci.c.svn-base
字号:
case PIPE_BULK: if (ed->ed_prev == NULL) { if (!ed->hwNextED) { ohci->hc_control &= ~OHCI_CTRL_BLE; writel (ohci->hc_control, &ohci->regs->control); } writel (m32_swap (*((__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 *)m32_swap (*((__u32 *)&ed->hwNextED)))->ed_prev = ed->ed_prev; } break; } ed->state = ED_UNLINK; return 0;}/*-------------------------------------------------------------------------*//* add/reinit an endpoint; this should be done once at the usb_set_configuration command, * but the USB stack is a little bit stateless so we do it at every transaction * if the state of the ed is ED_NEW then a dummy td is added and the state is changed to ED_UNLINK * in all other cases the state is left unchanged * the ed 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){ td_t *td; ed_t *ed_ret; volatile ed_t *ed; 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)) { err("ep_add_ed: pending delete"); /* pending delete request */ return NULL; } if (ed->state == ED_NEW) { ed->hwINFO = m32_swap (OHCI_ED_SKIP); /* skip ed */ /* dummy td; end of td list for ed */ td = td_alloc (usb_dev); ed->hwTailP = m32_swap (td); ed->hwHeadP = ed->hwTailP; ed->state = ED_UNLINK; ed->type = usb_pipetype (pipe); ohci_dev.ed_cnt++; } ed->hwINFO = m32_swap (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); return ed_ret;}/*-------------------------------------------------------------------------* * TD handling functions *-------------------------------------------------------------------------*//* enqueue next TD for this URB (OHCI spec 5.2.8.2) */static void td_fill (ohci_t *ohci, unsigned int info, void *data, int len, struct usb_device *dev, int index, urb_priv_t *urb_priv){ volatile td_t *td, *td_pt;#ifdef OHCI_FILL_TRACE int i;#endif if (index > urb_priv->length) { err("index > length"); return; } /* use this td as the next dummy */ td_pt = urb_priv->td [index]; td_pt->hwNextTD = 0; /* fill the old dummy TD */ td = urb_priv->td [index] = (td_t *)(m32_swap (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)) { for (i = 0; i < len; i++) printf("td->data[%d] %#2x ",i, ((unsigned char *)td->data)[i]); printf("\n"); }#endif if (!len) data = 0; td->hwINFO = m32_swap (info); td->hwCBP = m32_swap (data); if (data) td->hwBE = m32_swap (data + len - 1); else td->hwBE = 0; td->hwNextTD = m32_swap (td_pt); td->hwPSW [0] = m16_swap (((__u32)data & 0x0FFF) | 0xE000); /* append to queue */ td->ed->hwTailP = td->hwNextTD;}/*-------------------------------------------------------------------------*//* 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){ ohci_t *ohci = &gohci; int data_len = transfer_len; void *data; int cnt = 0; __u32 info = 0; unsigned int toggle = 0; /* 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))) { toggle = TD_T_TOGGLE; } else { toggle = TD_T_DATA0; usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 1); } urb->td_cnt = 0; if (data_len) data = buffer; else data = 0; switch (usb_pipetype (pipe)) { case PIPE_BULK: 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++; } 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); cnt++; if (!ohci->sleeping) writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */ break; case PIPE_CONTROL: info = TD_CC | TD_DP_SETUP | TD_T_DATA0; 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; /* 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_fill (ohci, info, data, 0, dev, cnt++, urb); if (!ohci->sleeping) writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */ break; } if (urb->length != cnt) dbg("TD LENGTH %d != CNT %d", urb->length, cnt);}/*-------------------------------------------------------------------------* * Done List handling functions *-------------------------------------------------------------------------*//* calculate the transfer length and update the urb */static void dl_transfer_length(td_t * td){ __u32 tdINFO, tdBE, tdCBP; urb_priv_t *lurb_priv = &urb_priv; tdINFO = m32_swap (td->hwINFO); tdBE = m32_swap (td->hwBE); tdCBP = m32_swap (td->hwCBP); if (!(usb_pipetype (lurb_priv->pipe) == PIPE_CONTROL && ((td->index == 0) || (td->index == lurb_priv->length - 1)))) { if (tdBE != 0) { if (td->hwCBP == 0) lurb_priv->actual_length += tdBE - td->data + 1; else lurb_priv->actual_length += tdCBP - td->data; } }}/*-------------------------------------------------------------------------*//* 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 = &urb_priv; 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); } } 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; lurb_priv = &urb_priv; tdINFO = m32_swap (td_list->hwINFO); ed = td_list->ed; 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]; } if (ed->state != ED_NEW) { 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); 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 DEBUGurb_priv.actual_length = 0;pkt_print(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 = 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: *(__u16 *) data_buf = m16_swap (1); OK (2); case RH_GET_STATUS | RH_INTERFACE: *(__u16 *) data_buf = m16_swap (0); OK (2); case RH_GET_STATUS | RH_ENDPOINT: *(__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)); OK (4); case RH_GET_STATUS | RH_OTHER | RH_CLASS: *(__u32 *) 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 ); 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); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -