📄 hc_isp116x.c
字号:
regval32 = READ_REG32(hci, HcRhDescriptorA); printk("HcRhDescriptorA %lx\n", regval32); regval32 = READ_REG32(hci, HcRhDescriptorB); printk("HcRhDescriptorB %lx\n", regval32); regval32 = READ_REG32(hci, HcRhStatus); printk("HcRhStatus %lx\n", regval32); regval32 = READ_REG32(hci, HcRhPortStatus); printk("HcRhPortStatus[1] %lx\n", regval32); regval16 = READ_REG16(hci, HcHardwareConfiguration); printk("HcHardwareConfiguration %x\n", regval16); regval16 = READ_REG16(hci, HcDMAConfiguration); printk("HcDMAConfiguration %x\n", regval16); regval16 = READ_REG16(hci, HcTransferCounter); printk("HcTransferCounter %x\n", regval16); regval16 = READ_REG16(hci, HcuPInterrupt); printk("HcuPInterrupt %x\n", regval16); regval16 = READ_REG16(hci, HcuPInterruptEnable); printk("HcuPInterruptEnable %x\n", regval16); regval16 = READ_REG16(hci, HcChipID); printk("HcChipID %x\n", regval16); regval16 = READ_REG16(hci, HcScratch); printk("HcScratch %x\n", regval16); regval16 = READ_REG16(hci, HcITLBufferLength); printk("HcITLBufferLength %x\n", regval16); regval16 = READ_REG16(hci, HcATLBufferLength); printk("HcATLBufferLength %x\n", regval16); regval16 = READ_REG16(hci, HcBufferStatus); printk("HcBufferStatus %x\n", regval16); regval16 = READ_REG16(hci, HcReadBackITL0Length); printk("HcReadBackITL0Length %x\n", regval16); regval16 = READ_REG16(hci, HcReadBackITL1Length); printk("HcReadBackITL1Length %x\n", regval16); regval16 = READ_REG16(hci, HcITLBufferPort); printk("HcITLBufferPort %x\n", regval16); regval16 = READ_REG16(hci, HcATLBufferPort); printk("HcATLBufferPort %x\n", regval16);}/*-------------------------------------------------------------------------*//* tl functions */static inline void hc_mark_last_trans (hci_t * hci) { hcipriv_t * hp = &hci->hp; __u8 * ptd = hp->tl; if (hp->tlp > 0) *(ptd + hp->tl_last) |= (1 << 3);}static inline void hc_flush_data_cache (hci_t * hci, void * data, int len) {}/*** Function Name : hc_add_trans** ** This function sets up the registers and transmit the USB packets.**** Called from hc_simple.c*/static inline int hc_add_trans (hci_t * hci, int len, void * data, int toggle, int maxps, int slow, int endpoint, int address, int pid, int format, int urb_state){ hcipriv_t * hp = &hci->hp; int last = 0; __u8 * ptd = hp->tl; int parts = 2; /* just send 4 packets of each kind at a frame, * other URBs also want some bandwitdh, and a NACK is cheaper * with less packets */ switch (hci->active_urbs) { case 1: parts = 8; break; case 2: parts = 6; break; case 3: parts = 4; break; case 4: parts = 3; break; case 5: parts = 2; break; default: parts = 2; } if (len > maxps * parts) len = maxps * parts; if (hp->units_left < ((len + 8 + 3) & ~0x3)) return -1; else hp->units_left -= (len + 8 + 3) & ~0x3; ptd += hp->tlp; hp->tl_last = hp->tlp + 3; ptd [0] = 0; ptd [1] = (toggle << 2) | (1 << 3) | (0xf << 4); ptd [2] = maxps; ptd [3] = ((maxps >> 8) & 0x3) | (slow << 2) | (last << 3) | (endpoint << 4); ptd [4] = len; ptd [5] = ((len >> 8) & 0x3) | (pid << 2); ptd [6] = address | (format << 7); ptd [7] = 0; if (pid != PID_IN && len) memcpy (ptd + 8, data, len); hp->tlp += ((len + 8 + 3) & ~0x3); return len;}/************************************************************************ * Function Name : hc_parse_trans * * This function checks the status of the transmitted or received packet * by parseing the PTD (Philips Transfer Desciptor, see page 26 of * datasheet) and copies the data from the device registers into a buffer. * * Used by hc_simple.c */static inline int hc_parse_trans (hci_t * hci, int * actbytes, __u8 * data, int * cc, int * toggle, int length,int pid, int urb_state){ hcipriv_t * hp = &hci->hp; int last = 0; int totbytes; __u8 *ptd = hp->tl + hp->tlp; *cc = (ptd [1] >> 4) & 0xf; last = (ptd [3] >> 3) & 0x1; *actbytes = ((ptd [1] & 0x3) << 8) | ptd [0]; totbytes = ((ptd [5] & 0x3) << 8) | ptd [4]; pid = (ptd [5] >> 2) & 0x3; if (*actbytes > length) *actbytes = length; if (pid == PID_IN && *actbytes) memcpy (data, ptd + 8, *actbytes); *toggle = (ptd [1] >> 2 & 1); if (*cc > 0 && *cc < 0xE && *cc != 9) *toggle = !*toggle;/* *active = (ptd[1] >> 3) & 0x1; *endpoint = ptd [3] >> 4; *address = ptd [6] & 0x7f; */ hp->tlp += ((totbytes + 8 + 3) & ~0x3); /* If we have failed to send data, ease off and give the USB bus a break */ if ( (totbytes != *actbytes) &&( (*cc == TD_CC_NOERROR) || (*cc == TD_CC_STALL) || (*cc == TD_DATAOVERRUN) || (*cc == TD_DATAUNDERRUN) || (*cc == TD_NOTACCESSED) ) ) { delay_factor = 5; } return !last;}/*-------------------------------------------------------------------------*/static void hc_start_int (hci_t * hci){#ifdef HC_SWITCH_INT int mask = SOFITLInt | ATLInt | OPR_Reg; WRITE_REG16 (hci, mask, HcuPInterrupt); WRITE_REG16 (hci, mask, HcuPInterruptEnable);#endif} static void hc_stop_int (hci_t * hci){#ifdef HC_SWITCH_INT WRITE_REG16 (hci, 0, HcuPInterruptEnable);#endif}/*** Interrupt Handler**** The ISP1161 will generate a SOF interrupt every 1ms**** It is inadvisable to put debug statements in the handler as you** will probably spend all your time in the handler doing nothing else!***/static irqreturn_t hc_interrupt (int irq, void * __hci, struct pt_regs * r){ hci_t * hci = __hci; hcipriv_t * hp = &hci->hp; int ints_uP, ints = 0, bstat = 0; int isExcessNak = 0;#ifdef HC_ENABLE_ISOC int iso_buffer_index = 0;#endif hci->regs = r; ints_uP = READ_REG16 (hci, HcuPInterrupt); WRITE_REG16 (hci, ints_uP, HcuPInterrupt); //printk(KERN_ALERT" uPInterruptstatus=%x\n", ints_uP); if ((ints_uP & OPR_Reg) && (ints = (READ_REG32 (hci, HcInterruptStatus)))) { //printk(KERN_ALERT" HcInterruptStatus=%x\n", ints); if (ints & OHCI_INTR_SO) { //dbg("USB Schedule overrun"); WRITE_REG32 (hci, OHCI_INTR_SO, HcInterruptEnable); } if (ints & OHCI_INTR_SF) { WRITE_REG32 (hci, OHCI_INTR_SF, HcInterruptEnable); } WRITE_REG32 (hci, ints, HcInterruptStatus); WRITE_REG32 (hci, OHCI_INTR_MIE, HcInterruptEnable); } hci->frame_number = GET_FRAME_NUMBER (hci); bstat = READ_REG16 (hci, HcBufferStatus); if (ints_uP & SOFITLInt) { hci->frame_number = GET_FRAME_NUMBER (hci);#ifdef HC_ENABLE_ISOC /* read itl1 first. if there is an buffer overflow HC will stop at itl1 There will be a quirks in sh_done_list if this happens !!!!! */ if ((bstat & ITL1BufferFull) && (bstat & ITL1BufferDone)) { hp->itl1_len = READ_REG16 (hci, HcReadBackITL1Length); if (hp->itl1_len > 0) { WRITE_REG16 (hci, hp->itl1_len, HcTransferCounter); READ_REGn16 (hci, HcITLBufferPort, hp->itl1_len, hp->tl); hp->tlp = 0; hci->td_array = &hci->i_td_array [1]; sh_done_list (hci,&isExcessNak); } iso_buffer_index = 1; } if ((bstat & ITL0BufferFull) && (bstat & ITL0BufferDone)) { hp->itl0_len = READ_REG16 (hci, HcReadBackITL0Length); if (hp->itl0_len > 0) { WRITE_REG16 (hci, hp->itl0_len, HcTransferCounter); READ_REGn16 (hci, HcITLBufferPort, hp->itl0_len, hp->tl); hp->tlp = 0; hci->td_array = &hci->i_td_array [0]; sh_done_list (hci,&isExcessNak); } iso_buffer_index = 0; } hp->tlp = 0; hci->td_array = &hci->i_td_array [iso_buffer_index]; sh_scan_iso_urb_list (hci, &hci->iso_list, hci->frame_number + 1); if (hp->tlp >0) { WRITE_REG16 (hci, hp->tlp, HcTransferCounter); WRITE_REGn16 (hci, HcITLBufferPort, hp->tlp, hp->tl); }#endif } if (ints_uP & ATLInt) { if ((bstat & ATLBufferFull) && (bstat & ATLBufferDone)) { if (hp->atl_len > 0) { WRITE_REG16 (hci, hp->atl_len, HcTransferCounter); READ_REGn16 (hci, HcATLBufferPort, hp->atl_len, hp->tl); hp->tlp = 0; hci->td_array = &hci->a_td_array; sh_done_list (hci,&isExcessNak); } hp->tlp = 0; } } if ( (hci->a_td_array.len == 0) &&(hci->i_td_array[0].len == 0) &&(hci->i_td_array[1].len == 0) ) sh_del_list (hci); /* If we want to introduce a delay before sending any more data, don't do anything here */ if (delay_factor > 0) { delay_factor--; return IRQ_HANDLED; } hci->td_array = &hci->a_td_array; bstat = READ_REG16 (hci, HcBufferStatus); if (hci->td_array->len == 0 && !(bstat & ATLBufferFull)) { hp->units_left = hp->atl_buffer_len; hp->tlp = 0; sh_schedule_trans (hci,0); hc_mark_last_trans (hci); hp->atl_len = hp->tlp; if (hp->atl_len > 0) { WRITE_REG16 (hci, hp->atl_len, HcTransferCounter); WRITE_REGn16 (hci, HcATLBufferPort, hp->atl_len, hp->tl); } } return IRQ_HANDLED;}static irqreturn_t isp116x_interrupt (int irq, void * __hci, struct pt_regs * r){ int int_status; int_status = ISP116x_INW(isp116x_ctl_stat); //printk(KERN_ALERT" isp116x int status=%x\n", int_status); if (int_status & 1) { hc_interrupt(irq, __hci, r); } if (int_status & 2) { } return IRQ_HANDLED;}/*-------------------------------------------------------------------------* * HC functions *-------------------------------------------------------------------------*//* reset the HC and BUS */static int hc_reset (hci_t * hci){ int timeout = 30; /* Disable HC interrupts */ WRITE_REG32 (hci, OHCI_INTR_MIE, HcInterruptDisable); dbg ("USB HC reset_hc usb-: ctrl = 0x%x ;", READ_REG32 (hci, HcControl)); /* Reset USB (needed by some controllers) */ WRITE_REG32 (hci, 0, HcControl); /* Write the correct reset value */ WRITE_REG16 (hci, 0xf6, HcSoftwareReset); /* HC Reset requires max 10 us delay */ WRITE_REG32 (hci, OHCI_HCR, HcCommandStatus); while ((READ_REG32 (hci, HcCommandStatus) & OHCI_HCR) != 0) { if (--timeout == 0) { err ("USB HC reset timed out!"); return -1; } udelay (1); } dbg("reset_hc done"); return 0;}/*-------------------------------------------------------------------------*//* Start an host controller, set the BUS operational * enable interrupts * connect the virtual root hub */static int hc_alloc_trans_buffer (hci_t * hci){ hcipriv_t * hp = &hci->hp; int maxlen; dbg("hc_alloc_trans_buffer"); hp->itl0_len = 0; hp->itl1_len = 0; hp->atl_len = 0; hp->itl_buffer_len = 1024; hp->atl_buffer_len = 4096 - 2 * hp->itl_buffer_len; /* 2048 */ WRITE_REG16 (hci, hp->itl_buffer_len, HcITLBufferLength); WRITE_REG16 (hci, hp->atl_buffer_len, HcATLBufferLength); /* Enable IRQ's */ WRITE_REG16 (hci,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -