📄 hc_isp116x.c
字号:
/*-------------------------------------------------------------------------*//*-------------------------------------------------------------------------* * isp1161 USB HCD for Linux Version 0.9.5 (10/28/2001) * Version Tango (05/11/2004) * * requires (includes) hc_simple.[hc] simple generic HCD frontend * * Roman Weissgaerber weissg@vienna.at (C) 2001 * * Thanks to Benjamin Herrenschmidt for debugging and the removing of * some bugs. * * adsynori 2004 *-------------------------------------------------------------------------* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * *-------------------------------------------------------------------------*//* V Tango 05/11/2004 ISOC transmission may not stop.(DATA IN) *//* V 0.9.5 10/28/2001 correct toggle on error *//* inw, outw macros; ISOC support *//* V 0.9 remove some bugs, ISOC still missing *//* V 0.8.1 9/5/2001 mv memcpy of in packet to hc *//* V 0.8 initial release */#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/delay.h>#include <linux/sched.h>#include <linux/malloc.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/smp_lock.h>#include <linux/list.h>#include <linux/ioport.h>#include <asm/io.h>#include <linux/usb.h>//#include "../core/hcd.h"#include "../hcd.h"#undef HC_URB_TIMEOUT#define HC_SWITCH_INT#define HC_ENABLE_ISOC#define OHCI_USE_NPS#include "hc_isp116x.h"#include "hc_simple_isp116x.h"//#define DEBUG1static int hc_verbose = 0;static int hc_error_verbose = 0;static int urb_debug = 0;#include "hc_simple_isp116x.c"#include "hc_isp116x_rh.c"/* it depends on your system *//* it's for CAT709 */static int irq = 74;static int hcport = 0xba00c000;static int hcport2 = 0xba00c002;static int wuport = 0x0; /* Not work */MODULE_PARM(hc_verbose,"i");MODULE_PARM_DESC(hc_verbose,"verbose startup messages, default is 1 (yes)");MODULE_PARM(hc_error_verbose,"i");MODULE_PARM_DESC(hc_error_verbose,"verbose error/warning messages, default is 0 (no)");MODULE_PARM(urb_debug,"i");MODULE_PARM_DESC(urb_debug,"debug urb messages, default is 0 (no)");MODULE_PARM(irq,"i");MODULE_PARM_DESC(irq,"IRQ 74 (default)");MODULE_PARM(hcport,"i");MODULE_PARM_DESC(hcport,"ISP116x PORT 0xba00c000");MODULE_PARM(hcport2,"i");MODULE_PARM_DESC(hcport2,"ISP116x PORT2 0xba00c002");//MODULE_PARM(wuport,"i");//MODULE_PARM_DESC(wuport,"WAKEUP PORT 0x240");/* it depends on your system *//* it's for CAT709 */#define WAIT_300NS ctrl_inw(0xa0000000);\ctrl_inw(0xa0000000);\ctrl_inw(0xa0000000);\ctrl_inw(0xa0000000);\ctrl_inw(0xa0000000);static inline void ISP116x_OUTW (int val, int addr){ ctrl_outw (val, addr);}static inline int ISP116x_INW (int addr){ return ctrl_inw (addr);}static inline int READ_REG32 (hci_t * hci, int regindex){ hcipriv_t * hp = &hci->hp; int val16, val; ISP116x_OUTW (regindex, hp->hcport2); WAIT_300NS val16 = ISP116x_INW (hp->hcport); val = val16 & 0xffff; val16 = ISP116x_INW (hp->hcport); val += val16 << 16; return val;}static inline int READ_REG16 (hci_t * hci, int regindex){ hcipriv_t * hp = &hci->hp; int val = 0; ISP116x_OUTW (regindex, hp->hcport2); WAIT_300NS val = ISP116x_INW (hp->hcport); return val;}static inline void READ_REGn16 (hci_t * hci, int regindex, int length, __u8 * buffer){ hcipriv_t * hp = &hci->hp; int i; int val = 0; ISP116x_OUTW (regindex, hp->hcport2); WAIT_300NS for (i = 0; i < length - 1; i += 2) { val = ISP116x_INW (hp->hcport); buffer [i] = val; buffer [i+1] = val >> 8; } if (length & 1) { val = ISP116x_INW (hp->hcport); buffer [length - 1] = val; }#ifdef DEBUG1 printk (" READ_REGn16: %d :", length); for (i = 0; i < length; i++)// for (i = 0; i < 8; i++) printk (" %2x", buffer [i]); printk("\n");#endif}static inline void WRITE_REG32 (hci_t * hci, unsigned int value, int regindex){ hcipriv_t * hp = &hci->hp; ISP116x_OUTW (regindex | 0x80, hp->hcport2); WAIT_300NS ISP116x_OUTW (value & 0xffff, hp->hcport); ISP116x_OUTW (value >> 16, hp->hcport);}static inline void WRITE_REG16 (hci_t * hci, unsigned int value, int regindex){ hcipriv_t * hp = &hci->hp; ISP116x_OUTW (regindex | 0x80, hp->hcport2); WAIT_300NS ISP116x_OUTW (value, hp->hcport);}static inline void WRITE_REG0 (hci_t * hci, int regindex){ hcipriv_t * hp = &hci->hp; ISP116x_OUTW (regindex | 0x80, hp->hcport2); WAIT_300NS}static inline void WRITE_REGn16 (hci_t * hci, int regindex, int length, __u8 * buffer){ hcipriv_t * hp = &hci->hp; int i; ISP116x_OUTW (regindex | 0x80, hp->hcport2); WAIT_300NS for (i = 0; i < length - 1; i += 2) { ISP116x_OUTW (buffer [i] + (buffer [i+1] << 8), hp->hcport); } if (length & 1) { ISP116x_OUTW (buffer [length - 1], hp->hcport); }#ifdef DEBUG1 printk (" WRITE_REGn16: %d :", length); for (i = 0; i < length; i++)// for (i = 0; i < 2; i++) printk (" %2x", buffer [i]); printk("\n");#endif}/*-------------------------------------------------------------------------*//* 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){}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){ hcipriv_t * hp = &hci->hp; int last = 0; __u8 * ptd = hp->tl; int parts = 2;// int mask; /* 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; if (format == 1){ last = 1;// toggle = 0;// maxps = 644+8;// len = 644+8; } 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;}static inline int hc_parse_trans (hci_t * hci, int * actbytes, void * data, int * cc, int * toggle, int length){ hcipriv_t * hp = &hci->hp; int last = 0; int totbytes; int pid; __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); 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); WRITE_REG16 (hci,InterruptPinEnable | DataBusWidth16 | DownstreamPort15KRSel, HcHardwareConfiguration);#endif}static void hc_stop_int (hci_t * hci){#ifdef HC_SWITCH_INT WRITE_REG16 (hci, 0, HcuPInterrupt); /* maybe need */ WRITE_REG16 (hci, 0, HcuPInterruptEnable); WRITE_REG16 (hci,DataBusWidth16 | DownstreamPort15KRSel, HcHardwareConfiguration);#endif}/* an interrupt happens */static void 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 iso_buffer_index = 0; if ((ints_uP = (READ_REG16 (hci, HcuPInterrupt) & READ_REG16 (hci, HcuPInterruptEnable))) == 0) { printk("int1 %x %x bstat %x\n", ints_uP, ints, bstat); return; } WRITE_REG16 (hci, ints_uP, HcuPInterrupt); if ((ints_uP & OPR_Reg) && (ints = (READ_REG32 (hci, HcInterruptStatus)))) { if (ints & OHCI_INTR_SO) { printk("USB Schedule overrun\n"); 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)) { if (bstat & ITL1BufferDone) { hp->itl1_len = READ_REG16 (hci, HcReadBackITL1Length); if (hp->itl1_len > 0) {//printk("bstat =%x hp->itl1_len=%d\n",bstat,hp->itl1_len); 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); } iso_buffer_index = 1; }// if ((bstat & ITL0BufferFull) && (bstat & ITL0BufferDone)) { if (bstat & ITL0BufferDone) { hp->itl0_len = READ_REG16 (hci, HcReadBackITL0Length);//printk("bstat =%x hp->itl0_len=%d\n",bstat,hp->itl0_len); 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); } iso_buffer_index = 0; } hp->tlp = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -