📄 usb_uhci.c
字号:
{
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 ,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;
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;
}
pci_read_config_byte(busdevfunc,PCI_INTERRUPT_LINE,&temp);
irqvec = temp;
irq_free_handler(irqvec);
USB_UHCI_PRINTF("Interrupt Line = %d, is %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);
return 0;
}
/* stop uhci
*/
int usb_lowlevel_stop(void)
{
if(irqvec==-1)
return 1;
irq_free_handler(irqvec);
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) {}
#endif
static 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)
*/
int uhci_submit_rh_msg(struct usb_device *dev, unsigned long pipe, void *buffer,int transfer_len,struct devrequest *cmd)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -