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

📄 farsync.c

📁 内核linux2.4.20,可跟rtlinux3.2打补丁 组成实时linux系统,编译内核
💻 C
📖 第 1 页 / 共 4 页
字号:
/* *      FarSync X21 driver for Linux (2.4.x kernel version) * *      Actually sync driver for X.21, V.35 and V.24 on FarSync T-series cards * *      Copyright (C) 2001 FarSite Communications Ltd. *      www.farsite.co.uk * *      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. * *      Author: R.J.Dunlop      <bob.dunlop@farsite.co.uk> */#include <linux/module.h>#include <linux/kernel.h>#include <linux/pci.h>#include <linux/ioport.h>#include <linux/netdevice.h>#include <linux/init.h>#include <linux/if_arp.h>#include <asm/uaccess.h>#include <net/syncppp.h>#include "farsync.h"/* *      Module info */MODULE_AUTHOR("R.J.Dunlop <bob.dunlop@farsite.co.uk>");MODULE_DESCRIPTION("FarSync T-Series X21 driver. FarSite Communications Ltd.");EXPORT_NO_SYMBOLS;/*      Driver configuration and global parameters *      ========================================== *//*      Number of ports (per card) supported */#define FST_MAX_PORTS           4/*      PCI vendor and device IDs */#define FSC_PCI_VENDOR_ID       0x1619  /* FarSite Communications Ltd */#define T2P_PCI_DEVICE_ID       0x0400  /* T2P X21 2 port card */#define T4P_PCI_DEVICE_ID       0x0440  /* T4P X21 4 port card *//*      Default parameters for the link */#define FST_TX_QUEUE_LEN        100     /* At 8Mbps a longer queue length is                                         * useful, the syncppp module forces                                         * this down assuming a slower line I                                         * guess.                                         */#define FST_MAX_MTU             8000    /* Huge but possible */#define FST_DEF_MTU             1500    /* Common sane value */#define FST_TX_TIMEOUT          (2*HZ)#ifdef ARPHRD_RAWHDLC#define ARPHRD_MYTYPE   ARPHRD_RAWHDLC  /* Raw frames */#else#define ARPHRD_MYTYPE   ARPHRD_HDLC     /* Cisco-HDLC (keepalives etc) */#endif/*      Card shared memory layout *      ========================= */#pragma pack(1)/*      This information is derived in part from the FarSite FarSync Smc.h *      file. Unfortunately various name clashes and the non-portability of the *      bit field declarations in that file have meant that I have chosen to *      recreate the information here. * *      The SMC (Shared Memory Configuration) has a version number that is *      incremented every time there is a significant change. This number can *      be used to check that we have not got out of step with the firmware *      contained in the .CDE files. */#define SMC_VERSION 11#define FST_MEMSIZE 0x100000    /* Size of card memory (1Mb) */#define SMC_BASE 0x00002000L    /* Base offset of the shared memory window main                                 * configuration structure */#define BFM_BASE 0x00010000L    /* Base offset of the shared memory window DMA                                 * buffers */#define LEN_TX_BUFFER 8192      /* Size of packet buffers */#define LEN_RX_BUFFER 8192#define LEN_SMALL_TX_BUFFER 256 /* Size of obsolete buffs used for DOS diags */#define LEN_SMALL_RX_BUFFER 256#define NUM_TX_BUFFER 2         /* Must be power of 2. Fixed by firmware */#define NUM_RX_BUFFER 8/* Interrupt retry time in milliseconds */#define INT_RETRY_TIME 2/*      The Am186CH/CC processors support a SmartDMA mode using circular pools *      of buffer descriptors. The structure is almost identical to that used *      in the LANCE Ethernet controllers. Details available as PDF from the *      AMD web site: http://www.amd.com/products/epd/processors/\ *                    2.16bitcont/3.am186cxfa/a21914/21914.pdf */struct txdesc {                 /* Transmit descriptor */        volatile u16 ladr;      /* Low order address of packet. This is a                                 * linear address in the Am186 memory space                                 */        volatile u8  hadr;      /* High order address. Low 4 bits only, high 4                                 * bits must be zero                                 */        volatile u8  bits;      /* Status and config */        volatile u16 bcnt;      /* 2s complement of packet size in low 15 bits.                                 * Transmit terminal count interrupt enable in                                 * top bit.                                 */                 u16 unused;    /* Not used in Tx */};struct rxdesc {                 /* Receive descriptor */        volatile u16 ladr;      /* Low order address of packet */        volatile u8  hadr;      /* High order address */        volatile u8  bits;      /* Status and config */        volatile u16 bcnt;      /* 2s complement of buffer size in low 15 bits.                                 * Receive terminal count interrupt enable in                                 * top bit.                                 */        volatile u16 mcnt;      /* Message byte count (15 bits) */};/* Convert a length into the 15 bit 2's complement *//* #define cnv_bcnt(len)   (( ~(len) + 1 ) & 0x7FFF ) *//* Since we need to set the high bit to enable the completion interrupt this * can be made a lot simpler */#define cnv_bcnt(len)   (-(len))/* Status and config bits for the above */#define DMA_OWN         0x80            /* SmartDMA owns the descriptor */#define TX_STP          0x02            /* Tx: start of packet */#define TX_ENP          0x01            /* Tx: end of packet */#define RX_ERR          0x40            /* Rx: error (OR of next 4 bits) */#define RX_FRAM         0x20            /* Rx: framing error */#define RX_OFLO         0x10            /* Rx: overflow error */#define RX_CRC          0x08            /* Rx: CRC error */#define RX_HBUF         0x04            /* Rx: buffer error */#define RX_STP          0x02            /* Rx: start of packet */#define RX_ENP          0x01            /* Rx: end of packet *//* Interrupts from the card are caused by various events and these are presented * in a circular buffer as several events may be processed on one physical int */#define MAX_CIRBUFF     32struct cirbuff {        u8 rdindex;             /* read, then increment and wrap */        u8 wrindex;             /* write, then increment and wrap */        u8 evntbuff[MAX_CIRBUFF];};/* Interrupt event codes. * Where appropriate the two low order bits indicate the port number */#define CTLA_CHG        0x18    /* Control signal changed */#define CTLB_CHG        0x19#define CTLC_CHG        0x1A#define CTLD_CHG        0x1B#define INIT_CPLT       0x20    /* Initialisation complete */#define INIT_FAIL       0x21    /* Initialisation failed */#define ABTA_SENT       0x24    /* Abort sent */#define ABTB_SENT       0x25#define ABTC_SENT       0x26#define ABTD_SENT       0x27#define TXA_UNDF        0x28    /* Transmission underflow */#define TXB_UNDF        0x29#define TXC_UNDF        0x2A#define TXD_UNDF        0x2B/* Port physical configuration. See farsync.h for field values */struct port_cfg {        u16  lineInterface;     /* Physical interface type */        u8   x25op;             /* Unused at present */        u8   internalClock;     /* 1 => internal clock, 0 => external */        u32  lineSpeed;         /* Speed in bps */};/* Finally sling all the above together into the shared memory structure. * Sorry it's a hodge podge of arrays, structures and unused bits, it's been * evolving under NT for some time so I guess we're stuck with it. * The structure starts at offset SMC_BASE. * See farsync.h for some field values. */struct fst_shared {                                /* DMA descriptor rings */        struct rxdesc rxDescrRing[FST_MAX_PORTS][NUM_RX_BUFFER];        struct txdesc txDescrRing[FST_MAX_PORTS][NUM_TX_BUFFER];                                /* Obsolete small buffers */        u8  smallRxBuffer[FST_MAX_PORTS][NUM_RX_BUFFER][LEN_SMALL_RX_BUFFER];        u8  smallTxBuffer[FST_MAX_PORTS][NUM_TX_BUFFER][LEN_SMALL_TX_BUFFER];        u8  taskStatus;         /* 0x00 => initialising, 0x01 => running,                                 * 0xFF => halted                                 */        u8  interruptHandshake; /* Set to 0x01 by adapter to signal interrupt,                                 * set to 0xEE by host to acknowledge interrupt                                 */        u16 smcVersion;         /* Must match SMC_VERSION */        u32 smcFirmwareVersion; /* 0xIIVVRRBB where II = product ID, VV = major                                 * version, RR = revision and BB = build                                 */        u16 txa_done;           /* Obsolete completion flags */        u16 rxa_done;        u16 txb_done;        u16 rxb_done;        u16 txc_done;        u16 rxc_done;        u16 txd_done;        u16 rxd_done;        u16 mailbox[4];         /* Diagnostics mailbox. Not used */        struct cirbuff interruptEvent;  /* interrupt causes */        u32 v24IpSts[FST_MAX_PORTS];    /* V.24 control input status */        u32 v24OpSts[FST_MAX_PORTS];    /* V.24 control output status */        struct port_cfg portConfig[FST_MAX_PORTS];        u16 clockStatus[FST_MAX_PORTS]; /* lsb: 0=> present, 1=> absent */        u16 cableStatus;                /* lsb: 0=> present, 1=> absent */        u16 txDescrIndex[FST_MAX_PORTS]; /* transmit descriptor ring index */        u16 rxDescrIndex[FST_MAX_PORTS]; /* receive descriptor ring index */        u16 portMailbox[FST_MAX_PORTS][2];      /* command, modifier */        u16 cardMailbox[4];                     /* Not used */                                /* Number of times that card thinks the host has                                 * missed an interrupt by not acknowledging                                 * within 2mS (I guess NT has problems)                                 */        u32 interruptRetryCount;                                /* Driver private data used as an ID. We'll not                                 * use this on Linux I'd rather keep such things                                 * in main memory rather than on the PCI bus                                 */        u32 portHandle[FST_MAX_PORTS];                                /* Count of Tx underflows for stats */        u32 transmitBufferUnderflow[FST_MAX_PORTS];                                /* Debounced V.24 control input status */        u32 v24DebouncedSts[FST_MAX_PORTS];                                /* Adapter debounce timers. Don't touch */        u32 ctsTimer[FST_MAX_PORTS];        u32 ctsTimerRun[FST_MAX_PORTS];        u32 dcdTimer[FST_MAX_PORTS];        u32 dcdTimerRun[FST_MAX_PORTS];        u32 numberOfPorts;      /* Number of ports detected at startup */        u16 _reserved[64];        u16 cardMode;           /* Bit-mask to enable features:                                 * Bit 0: 1 enables LED identify mode                                 */        u16 portScheduleOffset;        u32 endOfSmcSignature;  /* endOfSmcSignature MUST be the last member of                                 * the structure and marks the end of the shared                                 * memory. Adapter code initializes its value as                                 * END_SIG.                                 */};/* endOfSmcSignature value */#define END_SIG                 0x12345678/* Mailbox values. (portMailbox) */#define NOP             0       /* No operation */#define ACK             1       /* Positive acknowledgement to PC driver */#define NAK             2       /* Negative acknowledgement to PC driver */#define STARTPORT       3       /* Start an HDLC port */#define STOPPORT        4       /* Stop an HDLC port */#define ABORTTX         5       /* Abort the transmitter for a port */#define SETV24O         6       /* Set V24 outputs *//* Larger buffers are positioned in memory at offset BFM_BASE */struct buf_window {        u8 txBuffer[FST_MAX_PORTS][NUM_TX_BUFFER][LEN_TX_BUFFER];        u8 rxBuffer[FST_MAX_PORTS][NUM_RX_BUFFER][LEN_RX_BUFFER];};/* Calculate offset of a buffer object within the shared memory window */#define BUF_OFFSET(X)   ((unsigned int)&(((struct buf_window *)BFM_BASE)->X))#pragma pack()/*      Device driver private information *      ================================= *//*      Per port (line or channel) information */struct fst_port_info {        void                   *if_ptr; /* Some drivers describe this as a                                         * general purpose pointer. However if                                         * using syncPPP it has a very specific                                         * purpose: it must be the first item in                                         * the structure pointed to by dev->priv                                         * and must in turn point to the                                         * associated ppp_device structure.                                         */        struct fst_card_info   *card;   /* Card we're associated with */        int                     index;  /* Port index on the card */        int                     proto;  /* Protocol we are running */        int                     hwif;   /* Line hardware (lineInterface copy) */        int                     run;    /* Port is running */        int                     rxpos;  /* Next Rx buffer to use */        int                     txpos;  /* Next Tx buffer to use */        int                     txipos; /* Next Tx buffer to check for free */        int                     txcnt;  /* Count of Tx buffers in use */        struct net_device      *dev;    /* Kernel network device entry */        struct net_device_stats stats;  /* Standard statistics */        struct ppp_device       pppdev; /* Link to syncPPP */};/*      Per card information */struct fst_card_info {        char          *mem;             /* Card memory mapped to kernel space */        char          *ctlmem;          /* Control memory for PCI cards */        unsigned int   phys_mem;        /* Physical memory window address */        unsigned int   phys_ctlmem;     /* Physical control memory address */        unsigned int   irq;             /* Interrupt request line number */        unsigned int   nports;          /* Number of serial ports */        unsigned int   type;            /* Type index of card */        unsigned int   state;           /* State of card */        spinlock_t     card_lock;       /* Lock for SMP access */        unsigned short pci_conf;        /* PCI card config in I/O space */                                        /* Per port info */        struct fst_port_info ports[ FST_MAX_PORTS ];};/* *      Shared memory window access macros * *      We have a nice memory based structure above, which could be directly *      mapped on i386 but might not work on other architectures unless we use *      the readb,w,l and writeb,w,l macros. Unfortunately these macros take *      physical offsets so we have to convert. The only saving grace is that *      this should all collapse back to a simple indirection eventually. */#define WIN_OFFSET(X)   ((long)&(((struct fst_shared *)SMC_BASE)->X))#define FST_RDB(C,E)    readb ((C)->mem + WIN_OFFSET(E))#define FST_RDW(C,E)    readw ((C)->mem + WIN_OFFSET(E))#define FST_RDL(C,E)    readl ((C)->mem + WIN_OFFSET(E))#define FST_WRB(C,E,B)  writeb ((B), (C)->mem + WIN_OFFSET(E))#define FST_WRW(C,E,W)  writew ((W), (C)->mem + WIN_OFFSET(E))#define FST_WRL(C,E,L)  writel ((L), (C)->mem + WIN_OFFSET(E))/* *      Debug support */#if FST_DEBUGstatic int fst_debug_mask = { FST_DEBUG };/* Most common debug activity is to print something if the corresponding bit * is set in the debug mask. Note: this uses a non-ANSI extension in GCC to * support variable numbers of macro parameters. The inverted if prevents us * eating someone else's else clause. */#define dbg(F,fmt,A...) if ( ! ( fst_debug_mask & (F))) \                                ; \                        else \                                printk ( KERN_DEBUG FST_NAME ": " fmt, ## A )#else# define dbg(X...)      /* NOP */#endif/*      Printing short cuts */#define printk_err(fmt,A...)    printk ( KERN_ERR     FST_NAME ": " fmt, ## A )#define printk_warn(fmt,A...)   printk ( KERN_WARNING FST_NAME ": " fmt, ## A )#define printk_info(fmt,A...)   printk ( KERN_INFO    FST_NAME ": " fmt, ## A )/* *      PCI ID lookup table */static struct pci_device_id fst_pci_dev_id[] __devinitdata = {        { FSC_PCI_VENDOR_ID, T2P_PCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0,                                        FST_TYPE_T2P },        { FSC_PCI_VENDOR_ID, T4P_PCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0,                                        FST_TYPE_T4P },        { 0, }                          /* End */};MODULE_DEVICE_TABLE ( pci, fst_pci_dev_id );/*      Card control functions *      ====================== *//*      Place the processor in reset state * * Used to be a simple write to card control space but a glitch in the latest * AMD Am186CH processor means that we now have to do it by asserting and de- * asserting the PLX chip PCI Adapter Software Reset. Bit 30 in CNTRL register * at offset 0x50. */static inline voidfst_cpureset ( struct fst_card_info *card ){        unsigned int regval;        regval = inl ( card->pci_conf + 0x50 );        outl ( regval |  0x40000000, card->pci_conf + 0x50 );        outl ( regval & ~0x40000000, card->pci_conf + 0x50 );}/*      Release the processor from reset */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -