📄 usb_uhci.c
字号:
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 ,0,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,0,0,0L); temp=(unsigned long)&td_int[0]; for(n=1; n<8; n++) usb_fill_td(&td_int[n],temp,0,0,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; 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; 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(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(td->link) & UHCI_PTR_QH))) { /* check if a device is assigned with this td */ status=swap_32(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=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(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; /* * 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&0x20) && ((in16r(usb_base_addr+USBCMD) && USBCMD_RS)==0)) { out16r(usb_base_addr + USBCMD, USBCMD_RS | in16r(usb_base_addr + USBCMD)); } } 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; int busdevfunc;/* * HJF - configure IRQ and base from variables optionally. */ char *s; busdevfunc=pci_find_device(USB_UHCI_VEND_ID,USB_UHCI_DEV_ID,0); /* get PCI Device ID */ if(busdevfunc==-1) { printf("Error USB UHCI (%04X,%04X) not found\n",USB_UHCI_VEND_ID,USB_UHCI_DEV_ID); return -1; }#if 1 s = getenv("usb_irq"); if (s) { temp = atoi(s); pci_write_config_byte(busdevfunc, PCI_INTERRUPT_LINE, temp); } else#endif pci_read_config_byte(busdevfunc,PCI_INTERRUPT_LINE,&temp); s = getenv("usb_base"); if (s) { unsigned long temp2; temp2 = atoi(s); pci_write_config_dword(busdevfunc, PCI_BASE_ADDRESS_4, temp2|0x01); } irqvec = temp; irq_free_handler(irqvec); USB_UHCI_PRINTF("Interrupt Line = %d\n",irqvec); pci_read_config_byte(busdevfunc,PCI_INTERRUPT_PIN,&temp); USB_UHCI_PRINTF("Interrupt Pin = %ld\n",temp); pci_read_config_dword(busdevfunc,PCI_BASE_ADDRESS_4,&usb_base_addr); USB_UHCI_PRINTF("IO Base Address = 0x%lx\n",usb_base_addr); usb_base_addr&=0xFFFFFFF0; usb_base_addr+=CFG_ISA_IO_BASE_ADDRESS; rh.devnum = 0; usb_init_skel(); reset_hc(); start_hc(); irq_install_handler(irqvec, (interrupt_handler_t *)handle_usb_interrupt, NULL); irq_install_handler(0, (interrupt_handler_t *)handle_usb_interrupt, NULL); return 0;}/* stop uhci */int usb_lowlevel_stop(void){ if(irqvec==-1) return 1; irq_free_handler(irqvec); irq_free_handler(0); reset_hc(); irqvec=-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 */ 'u', /* __u8 Unicode */ 0, /* __u8 Unicode */ 'b', /* __u8 Unicode */ 0, /* __u8 Unicode */};/* * Root Hub Control Pipe (interrupt Pipes are not supported) */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -