⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hc_isp116x.c

📁 isp1161a USB主控制芯片驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
/*-------------------------------------------------------------------------* * 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 + -