📄 hc_isp116x.c
字号:
/*-------------------------------------------------------------------------* * isp1161 USB HCD for Linux Version 0.9.6 (??/??/2003) * * requires (includes) hc_simple.[hc] simple generic HCD frontend * * Original Author: * Roman Weissgaerber <weissg@vienna.at> (C) 2001 * * Others: * Benjamin Herrenschmidt <?> - debugging/bug fixes * Alex Bennee <kernel-hacker@bennee.com> - fixes for latest kernel * Andy Heaton <andy@braddahead.com> - evil hacks to get it working * * Version History: * 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 * *-------------------------------------------------------------------------* * 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 * *-------------------------------------------------------------------------*/#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/delay.h>#include <linux/sched.h>#include <linux/slab.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 <asm/delay.h>#include <asm/hardware.h>#include <linux/dma-mapping.h>#include <linux/usb.h>#include <core/hcd.h> //should add drivers/usb/core/ to INCLUDE in Makefile or cmdline/* Warning * debug generates a lot of output and can cause things to go * very slow */#undef DEBUG//#define DEBUG/* Debugging #define's, #define to nothing to disable */#ifdef DEBUG#define DBGERR(fmt, args...) printk(KERN_ALERT "isp116x: DBGERR " fmt,## args)#define DBGVERBOSE(fmt, args...) printk(KERN_ALERT "isp116x: DBGVERBOSE " fmt,## args)#define DBGFUNC(fmt, args...) printk(KERN_ALERT "isp116x: DBGFUNC " fmt,## args)#undef err#define err(fmt, args...) printk(KERN_ALERT "isp116x: err " fmt "\n",## args)#undef dbg#define dbg(fmt, args...) printk(KERN_ALERT "isp116x: dbg " fmt "\n",## args)#else#define DBGERR(fmt, args...) do { } while(0);#define DBGVERBOSE(fmt, args...) do { } while(0);#define DBGFUNC(fmt, args...) do { } while(0);#undef err#define err(fmt, args...) do { } while(0);#undef dbg#define dbg(fmt, args...) do { } while(0);#endif//#undef DBGFUNC//#define DBGFUNC(fmt, args...) printk(KERN_ALERT "isp116x: DBGFUNC " fmt,## args)/* define this to enable URB timeouts (handled by hc_simple.c)*/#undef HC_URB_TIMEOUT/* define this to dynamically turn interrupts on/off */#undef HC_SWITCH_INT/* define this to enable ISO packet transfers */#define HC_ENABLE_ISOC#include "hc_isp116x.h"#include "hc_simple.h"static int urb_debug = 0;static struct platform_device * isp116x_device=NULL; #include "hc_simple.c"#include "hc_isp116x_rh.c"/* old defaults static int irq = 10;static int hcport = 0x290;static int hcport2 = 0x292;static int wuport = 0x240;*//* Delay sending data */static unsigned int delay_factor = 0;/*** The ISP1161 has 4 ports:** Host Command/Data ports** Device Command/Data ports (not used in this driver)**** There is also a 5th port (wuport) which controls the status of the** signals to the ISP chip allowing it to be woken up from sleep, the** layout of this port will be hardware specific*/#if 0static int irq = 10;static unsigned long hc_data_port = 0xa3800000;static unsigned long hc_cmd_port = 0xa3800002;static unsigned long hc_wu_port = 0xa1e00000;#elsestatic int irq = 3;static unsigned long hc_data_port = IDE_BASE + (0xC0<<2);static unsigned long hc_cmd_port = IDE_BASE + (0xC1<<2);static unsigned long hc_wu_port = IDE_BASE ;static unsigned long isp116x_ctl_stat = IDE_BASE + (0xC4<<2);#endif/*** Hardware Config Register (see page 66 of datasheet)** ** This value is dependant on the hardware this driver is running on** and will need to be changed for each baord this driver runs on** depending on things like IRQ polarity**** Built in Resitors: xxx1 xxxx xxxx xxxx** Clock can be stopped:xxxx 0xxx xxxx xxxx** Use anaglog OC det: xxxx x1xx xxxx xxxx** DACKmode normal: xxxx xxx0 xxxx xxxx** EOTInput polarity: xxxx xxxx 1xxx xxxx** DACKInput polarity: xxxx xxxx x1xx xxxx** DREQOutput polarity: xxxx xxxx xx0x xxxx** databus width 16bit: xxxx xxxx xxx0 1xxx** IRQ polairty: xxxx xxxx xxxx x0xx** IRQ type (level): xxxx xxxx xxxx xx0x** IRQ enable: xxxx xxxx xxxx xxx0** = 0001 0100 1100 1000** = 0x14c8*/#if 0#define HCR_VALUE 0x14c8 //low level int#else#define HCR_VALUE 0x14cc //high level int#endif/* * Parameters for debugging verbosity */MODULE_PARM(urb_debug,"i");MODULE_PARM_DESC(urb_debug,"debug urb messages, default is 0 (no)");/* * Parameters for running */MODULE_PARM(irq,"i");MODULE_PARM_DESC(irq,"IRQ 3, 10 (default)");MODULE_PARM(hc_data_port,"i");MODULE_PARM_DESC(hc_data_port,"ISP116x Data PORT (Default=0x290)");MODULE_PARM(hc_cmd_port,"i");MODULE_PARM_DESC(hc_cmd_port,"ISP116x Command PORT (Default=0x292)");MODULE_PARM(hc_wu_port,"i");MODULE_PARM_DESC(hc_wu_port,"WAKEUP PORT (default=0x240)");static inline void ISP116x_OUTW (int val, unsigned long addr) { *(volatile u16 *)addr=val; // outw (val, addr); }static inline int ISP116x_INW (unsigned long addr){ return *(volatile u16 *)addr; // return inw (addr); }#if 0#ifdef ndelay#undef ndelay#endif// #define ndelay(n) (__builtin_constant_p(n) ? ((n) > 20000 ? __bad_ndelay() : __const_udelay((n) * 5)) : __ndelay(n))// #define ndelay(n) __const_udelay((n) * 5) #define ndelay(n) __const_udelay((n) * 50) #endif/*** These register READ/WRITE functions need to be protected by a** spinlock as they are a two stage non-atomic process. If you are** halfway through a register write an irq occurs you could end up** writting a bad value into the wrong register**** We also need to ensure we meet the access timing requirements (see** section 19.2 of datasheet) namely:**** A 300ns pause between cmd_port and data_port access** At least 110ns pause between subsequent reads/writes** */static spinlock_t isp116x_spinlock;static inline int READ_REG32 (hci_t * hci, int regindex){ unsigned long flags; hcipriv_t * hp = &hci->hp; int val16, val; spin_lock_irqsave(&isp116x_spinlock,flags); ISP116x_OUTW (regindex, hp->cmd_port); ndelay(300); val16 = ISP116x_INW (hp->data_port); val = val16; ndelay(110); val16 = ISP116x_INW (hp->data_port); val += val16 << 16; ndelay(110); spin_unlock_irqrestore(&isp116x_spinlock, flags); // DBGFUNC("READ_REG32 reg 0x%x=0x%x\n",regindex,val); return val;}static inline int READ_REG16 (hci_t * hci, int regindex) { unsigned long flags; hcipriv_t * hp = &hci->hp; int val = 0; spin_lock_irqsave(&isp116x_spinlock,flags); ISP116x_OUTW (regindex, hp->cmd_port); ndelay(300); val = ISP116x_INW (hp->data_port); ndelay(110); spin_unlock_irqrestore(&isp116x_spinlock, flags); // DBGFUNC("READ_REG16 reg 0x%x=0x%x\n",regindex,val); return val;}static inline void READ_REGn16 (hci_t * hci, int regindex, int length, __u8 * buffer){ unsigned long flags; hcipriv_t * hp = &hci->hp; int i; int val = 0; spin_lock_irqsave(&isp116x_spinlock,flags); ISP116x_OUTW (regindex, hp->cmd_port); ndelay(300); for (i = 0; i < length - 1; i += 2) { val = ISP116x_INW (hp->data_port); ndelay(110); buffer [i] = val; buffer [i+1] = val >> 8; } if (length & 1) { val = ISP116x_INW (hp->data_port); ndelay(110); } spin_unlock_irqrestore(&isp116x_spinlock, flags);#ifdef DEBUG printk (" READ_REGn16: %d :", length); for (i = 0; i < length; i++) printk (" %2x", buffer [i]); printk("\n");#endif}static inline void WRITE_REG32 (hci_t * hci, unsigned int value, int regindex) { unsigned long flags; hcipriv_t * hp = &hci->hp; spin_lock_irqsave(&isp116x_spinlock,flags); ISP116x_OUTW (regindex | 0x80, hp->cmd_port); ndelay(300); ISP116x_OUTW (value, hp->data_port); ndelay(110); ISP116x_OUTW (value >> 16, hp->data_port); ndelay(110); spin_unlock_irqrestore(&isp116x_spinlock, flags); //DBGFUNC("WRITE_REG32 reg 0x%x=>0x%x\n",regindex,value);}static inline void WRITE_REG16 (hci_t * hci, unsigned int value, int regindex) { unsigned long flags; hcipriv_t * hp = &hci->hp; spin_lock_irqsave(&isp116x_spinlock,flags); ISP116x_OUTW (regindex | 0x80, hp->cmd_port); ndelay(300); ISP116x_OUTW (value, hp->data_port); ndelay(110); spin_unlock_irqrestore(&isp116x_spinlock, flags); //DBGFUNC("WRITE_REG16 reg 0x%x=>0x%x\n",regindex,value);}static inline void WRITE_REGn16 (hci_t * hci, int regindex, int length, __u8 * buffer) { unsigned long flags; hcipriv_t * hp = &hci->hp; int i; spin_lock_irqsave(&isp116x_spinlock,flags); ISP116x_OUTW (regindex | 0x80, hp->cmd_port); ndelay(300); for (i = 0; i < length - 1; i += 2) { ISP116x_OUTW (buffer [i] + (buffer [i+1] << 8), hp->data_port); ndelay(110); } if (length & 1) { ISP116x_OUTW (buffer [length - 1], hp->data_port); ndelay(110); } spin_unlock_irqrestore(&isp116x_spinlock, flags);#ifdef DEBUG printk (" WRITE_REGn16: %d :", length); for (i = 0; i < length; i++) printk (" %2x", buffer [i]); printk("\n");#endif}#include "dc_isp116x.c"/*-------------------------------------------------------------------------*//* debug function */static void dump_regs(hci_t * hci){ long regval32; short regval16; printk("Register settings\n"); regval32 = READ_REG32(hci, HcRevision); printk("HcRevision %lx\n", regval32); regval32 = READ_REG32(hci, HcControl); printk("HcControl %lx\n", regval32); regval32 = READ_REG32(hci, HcCommandStatus); printk("HcCommandStatus %lx\n", regval32); regval32 = READ_REG32(hci, HcInterruptStatus); printk("HcInterruptStatus %lx\n", regval32); regval32 = READ_REG32(hci, HcInterruptEnable); printk("HcInterruptEnable %lx\n", regval32); regval32 = READ_REG32(hci, HcInterruptDisable); printk("HcInterruptDisable %lx\n", regval32); regval32 = READ_REG32(hci, HcFmInterval); printk("HcFmInterval %lx\n", regval32); regval32 = READ_REG32(hci, HcFmRemaining); printk("HcFmRemaining %lx\n", regval32); regval32 = READ_REG32(hci, HcFmNumber); printk("HcFmNumber %lx\n", regval32); regval32 = READ_REG32(hci, HcLSThreshold); printk("HcLSThreshold %lx\n", regval32);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -