📄 usb_uhci.c
字号:
*/uhci_td_t *uhci_alloc_int_td(void){ int i; for (i = 0; i < USB_MAX_TEMP_INT_TD; i++) { if (tmp_int_td[i].dev_ptr == 0) /* no device assigned -> free TD */ return &tmp_int_td[i]; } return NULL;}/*------------------------------------------------------------------- * submits USB interrupt (ie. polling ;-) */int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer, int transfer_len, int interval){ int nint, n; unsigned long status, destination; unsigned long info, tmp; uhci_td_t *mytd; if (interval < 0 || interval >= 256) return -1; if (interval == 0) nint = 0; else { for (nint = 0, n = 1; nint <= 8; nint++, n += n) { /* round interval down to 2^n */ if (interval < n) { interval = n / 2; break; } } nint--; } USB_UHCI_PRINTF("Rounded interval to %i, chain %i\n", interval, nint); mytd = uhci_alloc_int_td(); if (mytd == NULL) { printf("No free INT TDs found\n"); return -1; } status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC | (3 << 27);/* (urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27);*/ destination = (pipe & PIPE_DEVEP_MASK) | usb_packetid(pipe) | (((transfer_len - 1) & 0x7ff) << 21); info = destination | (usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)) << TD_TOKEN_TOGGLE); tmp = swap_32(td_int[nint].link); usb_fill_td(mytd, tmp, status, info, (unsigned long)buffer, (unsigned long)dev); /* Link it */ tmp = swap_32((unsigned long)mytd); td_int[nint].link = tmp; usb_dotoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)); return 0;}/********************************************************************** * Low Level functions */void reset_hc(void){ /* Global reset for 100ms */ out16r(usb_base_addr + USBPORTSC1, 0x0204); out16r(usb_base_addr + USBPORTSC2, 0x0204); out16r(usb_base_addr + USBCMD, USBCMD_GRESET | USBCMD_RS); /* Turn off all interrupts */ out16r(usb_base_addr + USBINTR, 0); wait_ms(50); out16r(usb_base_addr + USBCMD, 0); wait_ms(10);}void start_hc(void){ int timeout = 1000; while (in16r(usb_base_addr + USBCMD) & USBCMD_HCRESET) { if (!--timeout) { printf("USBCMD_HCRESET timed out!\n"); break; } } /* Turn on all interrupts */ out16r(usb_base_addr + USBINTR, USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP); /* Start at frame 0 */ out16r(usb_base_addr + USBFRNUM, 0); /* set Framebuffer base address */ out32r(usb_base_addr + USBFLBASEADD, (unsigned long)&framelist); /* Run and mark it configured with a 64-byte max packet */ out16r(usb_base_addr + USBCMD, USBCMD_RS | USBCMD_CF | USBCMD_MAXP);}/* Initialize the skeleton */void usb_init_skel(void){ unsigned long temp; int n; for (n = 0; n < USB_MAX_TEMP_INT_TD; n++) tmp_int_td[n].dev_ptr = 0L; /* no devices connected */ /* last td */ usb_fill_td(&td_last, UHCI_PTR_TERM, TD_CTRL_IOC, USB_PID_OUT, 0, 0L); /* usb_fill_td(&td_last,UHCI_PTR_TERM,0,0,0); */ /* End Queue Header */ usb_fill_qh(&qh_end, UHCI_PTR_TERM, (unsigned long)&td_last); /* Bulk Queue Header */ temp = (unsigned long)&qh_end; usb_fill_qh(&qh_bulk, temp | UHCI_PTR_QH, UHCI_PTR_TERM); /* Control Queue Header */ temp = (unsigned long)&qh_bulk; usb_fill_qh(&qh_cntrl, temp | UHCI_PTR_QH, UHCI_PTR_TERM); /* 1ms Interrupt td */ temp = (unsigned long)&qh_cntrl; usb_fill_td(&td_int[0], temp | UHCI_PTR_QH, 0, USB_PID_OUT, 0, 0L); temp = (unsigned long)&td_int[0]; for (n = 1; n < 8; n++) usb_fill_td(&td_int[n], temp, 0, USB_PID_OUT, 0, 0L); for (n = 0; n < 1024; n++) { /* link all framelist pointers to one of the interrupts */ int m, o; if ((n & 127) == 127) framelist[n] = swap_32((unsigned long)&td_int[0]); else for (o = 1, m = 2; m <= 128; o++, m += m) if ((n & (m - 1)) == ((m - 1) / 2)) framelist[n] = swap_32((unsigned long)&td_int[o]); }}/* check the common skeleton for completed transfers, and update the status * of the "connected" device. Called from the IRQ routine. */void usb_check_skel(void){ struct usb_device *dev; /* start with the control qh */ if (qh_cntrl.dev_ptr != 0) { /* it's a device assigned check if this caused IRQ */ dev = (struct usb_device *)qh_cntrl.dev_ptr; /* Flush cache now that hardware updated DATA and TDs/QHs */ if (!leon3_snooping_avail) sparc_dcache_flush_all(); usb_get_td_status(&tmp_td[0], dev); /* update status */ if (!(dev->status & USB_ST_NOT_PROC)) { /* is not active anymore, disconnect devices */ qh_cntrl.dev_ptr = 0; } } /* now process the bulk */ if (qh_bulk.dev_ptr != 0) { /* it's a device assigned check if this caused IRQ */ dev = (struct usb_device *)qh_bulk.dev_ptr; /* Flush cache now that hardware updated DATA and TDs/QHs */ if (!leon3_snooping_avail) sparc_dcache_flush_all(); usb_get_td_status(&tmp_td[0], dev); /* update status */ if (!(dev->status & USB_ST_NOT_PROC)) { /* is not active anymore, disconnect devices */ qh_bulk.dev_ptr = 0; } }}/* check the interrupt chain, ubdate the status of the appropriate device, * call the appropriate irqhandler and reactivate the TD if the irqhandler * returns with 1 */void usb_check_int_chain(void){ int i, res; unsigned long link, status; struct usb_device *dev; uhci_td_t *td, *prevtd; for (i = 0; i < 8; i++) { prevtd = &td_int[i]; /* the first previous td is the skeleton td */ link = swap_32(READ32(&td_int[i].link)) & 0xfffffff0; /* next in chain */ td = (uhci_td_t *) link; /* assign it */ /* all interrupt TDs are finally linked to the td_int[0]. * so we process all until we find the td_int[0]. * if int0 chain points to a QH, we're also done */ while (((i > 0) && (link != (unsigned long)&td_int[0])) || ((i == 0) && !(swap_32(READ32(&td->link)) & UHCI_PTR_QH))) { /* check if a device is assigned with this td */ status = swap_32(READ32(&td->status)); if ((td->dev_ptr != 0L) && !(status & TD_CTRL_ACTIVE)) { /* td is not active and a device is assigned -> call irqhandler */ dev = (struct usb_device *)td->dev_ptr; dev->irq_act_len = ((status & 0x7FF) == 0x7FF) ? 0 : (status & 0x7FF) + 1; /* transfered length */ dev->irq_status = usb_uhci_td_stat(status); /* get status */ res = dev->irq_handle(dev); /* call irqhandler */ if (res == 1) { /* reactivate */ status |= TD_CTRL_ACTIVE; td->status = swap_32(status); prevtd = td; /* previous td = this td */ } else { prevtd->link = READ32(&td->link); /* link previous td directly to the nex td -> unlinked */ /* remove device pointer */ td->dev_ptr = 0L; } } /* if we call the irq handler */ link = swap_32(READ32(&td->link)) & 0xfffffff0; /* next in chain */ td = (uhci_td_t *) link; /* assign it */ } /* process all td in this int chain */ } /* next interrupt chain */}/* usb interrupt service routine. */void handle_usb_interrupt(void){ unsigned short status; static int error = 0; /* * Read the interrupt status, and write it back to clear the * interrupt cause */ status = in16r(usb_base_addr + USBSTS); if (!status) /* shared interrupt, not mine */ return; if (status != 1) { /* remove host controller halted state */ if ((status & (USBSTS_HCPE | USBSTS_HCH)) == (USBSTS_HCPE | USBSTS_HCH)) { /* Stop due to bug in driver, or hardware */ out16r(usb_base_addr + USBSTS, status); out16r(usb_base_addr + USBCMD, USBCMD_HCRESET | USBCMD_GRESET); printf ("GRUSB: HW detected error(s) in USB Descriptors (STS: 0x%x)\n", status); usb_show_td(8); return; } else if ((status & 0x20) && ((in16r(usb_base_addr + USBCMD) & USBCMD_RS) == 0)) { if (error < 10) { out16r(usb_base_addr + USBCMD, USBCMD_RS | in16r(usb_base_addr + USBCMD)); error++; } } else error = 0; } usb_check_int_chain(); /* call interrupt handlers for int tds */ usb_check_skel(); /* call completion handler for common transfer routines */ out16r(usb_base_addr + USBSTS, status);}/* init uhci */int usb_lowlevel_init(void){ unsigned char temp; ambapp_ahbdev ahbdev; /* Find GRUSB core using AMBA Plug&Play information */ if (ambapp_ahbslv_first(VENDOR_GAISLER, GAISLER_UHCI, &ahbdev) != 1) { printf("USB UHCI: Failed to find GRUSB controller\n"); return -1; } usb_base_addr = ahbdev.address[0]; grusb_irq = ahbdev.irq; /* usb_base_addr = 0xfffa0000; grusb_irq = 10; */#ifdef USB_UHCI_DEBUG grusb_show_regs();#endif memset(td_int, 0, sizeof(td_int)); memset(tmp_td, 0, sizeof(tmp_td)); memset(tmp_int_td, 0, sizeof(tmp_int_td)); memset(&qh_cntrl, 0, sizeof(qh_cntrl)); memset(&qh_end, 0, sizeof(qh_end)); memset(&td_last, 0, sizeof(td_last)); irq_free_handler(grusb_irq); USB_UHCI_PRINTF("GRUSB: at 0x%lx irq %d\n", usb_base_addr, grusb_irq); rh.devnum = 0; usb_init_skel(); reset_hc(); start_hc(); irq_install_handler(grusb_irq, (interrupt_handler_t *) handle_usb_interrupt, NULL); return 0;}/* stop uhci */int usb_lowlevel_stop(void){ if (grusb_irq == -1) return 1; irq_free_handler(grusb_irq); reset_hc(); grusb_irq = -1; return 0;}/******************************************************************************************* * Virtual Root Hub * Since the uhci does not have a real HUB, we simulate one ;-) */#undef USB_RH_DEBUG#ifdef USB_RH_DEBUG#define USB_RH_PRINTF(fmt,args...) printf (fmt ,##args)static void usb_display_wValue(unsigned short wValue, unsigned short wIndex);static void usb_display_Req(unsigned short req);#else#define USB_RH_PRINTF(fmt,args...)static void usb_display_wValue(unsigned short wValue, unsigned short wIndex){}static void usb_display_Req(unsigned short req){}#endifstatic unsigned char root_hub_dev_des[] = { 0x12, /* __u8 bLength; */ 0x01, /* __u8 bDescriptorType; Device */ 0x00, /* __u16 bcdUSB; v1.0 */ 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, 0x01, /* __u8 iManufacturer; */ 0x00, /* __u8 iProduct; */ 0x00, /* __u8 iSerialNumber; */ 0x01 /* __u8 bNumConfigurations; */};/* Configuration descriptor */static unsigned char 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 */ 0x08, /* __u16 ep_wMaxPacketSize; 8 Bytes */ 0x00, 0xff /* __u8 ep_bInterval; 255 ms */};static unsigned char root_hub_hub_des[] = { 0x09, /* __u8 bLength; */ 0x29, /* __u8 bDescriptorType; Hub-descriptor */ 0x02, /* __u8 bNbrPorts; */ 0x00, /* __u16 wHubCharacteristics; */ 0x00, 0x01, /* __u8 bPwrOn2pwrGood; 2ms */ 0x00, /* __u8 bHubContrCurrent; 0 mA */ 0x00, /* __u8 DeviceRemovable; *** 7 Ports max *** */ 0xff /* __u8 PortPwrCtrlMask; *** 7 ports max *** */};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 */ 'U', /* __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 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -