📄 synclink.c
字号:
/* * linux/drivers/char/synclink.c * * Device driver for Microgate SyncLink ISA and PCI * high speed multiprotocol serial adapters. * * written by Paul Fulghum for Microgate Corporation * paulkf@microgate.com * * Microgate and SyncLink are trademarks of Microgate Corporation * * Derived from serial.c written by Theodore Ts'o and Linus Torvalds * * Original release 01/11/99 * * This code is released under the GNU General Public License (GPL) * * This driver is primarily intended for use in synchronous * HDLC mode. Asynchronous mode is also provided. * * When operating in synchronous mode, each call to mgsl_write() * contains exactly one complete HDLC frame. Calling mgsl_put_char * will start assembling an HDLC frame that will not be sent until * mgsl_flush_chars or mgsl_write is called. * * Synchronous receive data is reported as complete frames. To accomplish * this, the TTY flip buffer is bypassed (too small to hold largest * frame and may fragment frames) and the line discipline * receive entry point is called directly. * * This driver has been tested with a slightly modified ppp.c driver * for synchronous PPP. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ #define VERSION(ver,rel,seq) (((ver)<<16) | ((rel)<<8) | (seq))#define BREAKPOINT() asm(" int $3");#define MAX_ISA_DEVICES 10#include <linux/config.h>#include <linux/module.h>#include <linux/errno.h>#include <linux/signal.h>#include <linux/sched.h>#include <linux/timer.h>#include <linux/interrupt.h>#include <linux/pci.h>#include <linux/tty.h>#include <linux/tty_flip.h>#include <linux/serial.h>#include <linux/major.h>#include <linux/string.h>#include <linux/fcntl.h>#include <linux/ptrace.h>#include <linux/ioport.h>#include <linux/mm.h>#include <linux/malloc.h>#if LINUX_VERSION_CODE >= VERSION(2,1,0)#include <linux/vmalloc.h>#include <linux/init.h>#include <asm/serial.h>#else#include <linux/bios32.h>#endif#include <linux/delay.h>#include <linux/ioctl.h>#include <asm/system.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/dma.h>#include <asm/bitops.h>#include <asm/types.h>#include <linux/termios.h>#include <linux/tqueue.h>#if LINUX_VERSION_CODE >= VERSION(2,1,4)#include <asm/segment.h>#define GET_USER(error,value,addr) error = get_user(value,addr)#define COPY_FROM_USER(error,dest,src,size) error = copy_from_user(dest,src,size) ? -EFAULT : 0#define PUT_USER(error,value,addr) error = put_user(value,addr)#define COPY_TO_USER(error,dest,src,size) error = copy_to_user(dest,src,size) ? -EFAULT : 0#if LINUX_VERSION_CODE >= VERSION(2,1,5)#include <asm/uaccess.h>#endif#else /* 2.0.x and 2.1.x before 2.1.4 */#define GET_USER(error,value,addr) \do { \ error = verify_area (VERIFY_READ, (void *) addr, sizeof (value)); \ if (error == 0) \ value = get_user(addr); \} while (0)#define COPY_FROM_USER(error,dest,src,size) \do { \ error = verify_area (VERIFY_READ, (void *) src, size); \ if (error == 0) \ memcpy_fromfs (dest, src, size); \} while (0)#define PUT_USER(error,value,addr) \do { \ error = verify_area (VERIFY_WRITE, (void *) addr, sizeof (value)); \ if (error == 0) \ put_user (value, addr); \} while (0)#define COPY_TO_USER(error,dest,src,size) \do { \ error = verify_area (VERIFY_WRITE, (void *) dest, size); \ if (error == 0) \ memcpy_tofs (dest, src, size); \} while (0)#endif#if LINUX_VERSION_CODE < VERSION(2,1,0)/* * This is used to figure out the divisor speeds and the timeouts */static int baud_table[] = { 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800, 0 };#define __init#define ioremap(a,b) vremap((a),(b))#define iounmap(a) vfree((a))#define SERIAL_TYPE_NORMAL 1#define SERIAL_TYPE_CALLOUT 2typedef int spinlock_t;#define spin_lock_irqsave(a,b) {save_flags((b));cli();}#define spin_unlock_irqrestore(a,b) {restore_flags((b));}#define spin_lock(a)#define spin_unlock(a)#define schedule_timeout(a){current->timeout = jiffies + (a); schedule();}#define signal_pending(a) ((a)->signal & ~(a)->blocked)#endif#include "linux/synclink.h"#define RCLRVALUE 0xffffMGSL_PARAMS default_params = { MGSL_MODE_HDLC, /* unsigned long mode */ 0, /* unsigned char loopback; */ HDLC_FLAG_UNDERRUN_ABORT15, /* unsigned short flags; */ HDLC_ENCODING_NRZI_SPACE, /* unsigned char encoding; */ 0, /* unsigned long clock_speed; */ 0xff, /* unsigned char addr_filter; */ HDLC_CRC_16_CCITT, /* unsigned short crc_type; */ HDLC_PREAMBLE_LENGTH_8BITS, /* unsigned char preamble_length; */ HDLC_PREAMBLE_PATTERN_NONE, /* unsigned char preamble; */ 9600, /* unsigned long data_rate; */ 8, /* unsigned char data_bits; */ 1, /* unsigned char stop_bits; */ ASYNC_PARITY_NONE /* unsigned char parity; */};#define SHARED_MEM_ADDRESS_SIZE 0x40000#define BUFFERLISTSIZE (PAGE_SIZE)#define DMABUFFERSIZE (PAGE_SIZE)#define MAXRXFRAMES 7typedef struct _DMABUFFERENTRY{ u32 phys_addr; /* 32-bit flat physical address of data buffer */ u16 count; /* buffer size/data count */ u16 status; /* Control/status field */ u16 rcc; /* character count field */ u16 reserved; /* padding required by 16C32 */ u32 link; /* 32-bit flat link to next buffer entry */ char *virt_addr; /* virtual address of data buffer */ u32 phys_entry; /* physical address of this buffer entry */} DMABUFFERENTRY, *DMAPBUFFERENTRY;/* The queue of BH actions to be performed */#define BH_TYPE_RECEIVE_DATA 1#define BH_TYPE_RECEIVE_STATUS 2#define BH_TYPE_RECEIVE_DMA 3#define BH_TYPE_TRANSMIT_DATA 4#define BH_TYPE_TRANSMIT_STATUS 5#define BH_TYPE_STATUS 6typedef struct _BH_EVENT { unsigned char type; /* Set by interrupt routines to reqst */ u16 status; struct _BH_EVENT *link; } BH_EVENT, *BH_QUEUE; /* Queue of BH actions to be done. */#define MAX_BH_QUEUE_ENTRIES 200#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))/* * Device instance data structure */ struct mgsl_struct { int magic; int flags; int count; /* count of opens */ int line; unsigned short close_delay; unsigned short closing_wait; /* time to wait before closing */ struct mgsl_icount icount; struct termios normal_termios; struct termios callout_termios; struct tty_struct *tty; int timeout; int x_char; /* xon/xoff character */ int blocked_open; /* # of blocked opens */ long session; /* Session of opening process */ long pgrp; /* pgrp of opening process */ u16 read_status_mask; u16 ignore_status_mask; unsigned char *xmit_buf; int xmit_head; int xmit_tail; int xmit_cnt; struct wait_queue *open_wait; struct wait_queue *close_wait; struct wait_queue *status_event_wait_q; struct wait_queue *event_wait_q; struct timer_list tx_timer; /* HDLC transmit timeout timer */ struct mgsl_struct *next_device; /* device list link */ spinlock_t irq_spinlock; /* spinlock for synchronizing with ISR */ struct tq_struct task; /* task structure for scheduling bh */ u32 EventMask; /* event trigger mask */ u32 RecordedEvents; /* pending events */ u32 max_frame_size; /* as set by device config */ BH_EVENT bh_queue[MAX_BH_QUEUE_ENTRIES]; /* Pointer to alloc'ed block */ BH_QUEUE bh_queue_head; /* Queue of BH actions */ BH_QUEUE bh_queue_tail; /* Tail of above for perf. */ BH_QUEUE free_bh_queue_head; /* Queue of Free BH */ BH_QUEUE free_bh_queue_tail; /* Tail of above for perf. */ BH_QUEUE bh_action; /* Action for BH */ int bh_running; /* Protection from multiple */ int isr_overflow; int bh_requested; char *buffer_list; /* virtual address of Rx & Tx buffer lists */ unsigned long buffer_list_phys; unsigned int rx_buffer_count; /* count of total allocated Rx buffers */ DMABUFFERENTRY *rx_buffer_list; /* list of receive buffer entries */ unsigned int current_rx_buffer; unsigned int tx_buffer_count; /* count of total allocated Tx buffers */ DMABUFFERENTRY *tx_buffer_list; /* list of transmit buffer entries */ int rx_enabled; int rx_overflow; int tx_enabled; int tx_active; u32 idle_mode; u16 cmr_value; char device_name[25]; /* device instance name */ unsigned int bus_type; /* expansion bus type (ISA,EISA,PCI) */ unsigned char bus; /* expansion bus number (zero based) */ unsigned char function; /* PCI device number */ unsigned int io_base; /* base I/O address of adapter */ unsigned int io_addr_size; /* size of the I/O address range */ int io_addr_requested; /* nonzero if I/O address requested */ unsigned int irq_level; /* interrupt level */ unsigned long irq_flags; int irq_requested; /* nonzero if IRQ requested */ unsigned int dma_level; /* DMA channel */ int dma_requested; /* nonzero if dma channel requested */ u16 mbre_bit; u16 loopback_bits; u16 usc_idle_mode; MGSL_PARAMS params; /* communications parameters */ unsigned char serial_signals; /* current serial signal states */ int irq_occurred; /* for diagnostics use */ unsigned int init_error; /* Initialization startup error (DIAGS) */ int fDiagnosticsmode; /* Driver in Diagnostic mode? (DIAGS) */ u32 last_mem_alloc; unsigned char* memory_base; /* shared memory address (PCI only) */ u32 phys_memory_base; unsigned char* lcr_base; /* local config registers (PCI only) */ u32 phys_lcr_base; u32 lcr_offset; u32 misc_ctrl_value; char flag_buf[HDLC_MAX_FRAME_SIZE]; char char_buf[HDLC_MAX_FRAME_SIZE]; BOOLEAN drop_rts_on_tx_done;};#define MGSL_MAGIC 0x5401/* * The size of the serial xmit buffer is 1 page, or 4096 bytes */#define SERIAL_XMIT_SIZE 4096/* * These macros define the offsets used in calculating the * I/O address of the specified USC registers. */#define DCPIN 2 /* Bit 1 of I/O address */#define SDPIN 4 /* Bit 2 of I/O address */#define DCAR 0 /* DMA command/address register */#define CCAR SDPIN /* channel command/address register */#define DATAREG DCPIN + SDPIN /* serial data register */#define MSBONLY 0x41#define LSBONLY 0x40/* * These macros define the register address (ordinal number) * used for writing address/value pairs to the USC. */#define CMR 0x02 /* Channel mode Register */#define CCSR 0x04 /* Channel Command/status Register */#define CCR 0x06 /* Channel Control Register */#define PSR 0x08 /* Port status Register */#define PCR 0x0a /* Port Control Register */#define TMDR 0x0c /* Test mode Data Register */#define TMCR 0x0e /* Test mode Control Register */#define CMCR 0x10 /* Clock mode Control Register */#define HCR 0x12 /* Hardware Configuration Register */#define IVR 0x14 /* Interrupt Vector Register */#define IOCR 0x16 /* Input/Output Control Register */#define ICR 0x18 /* Interrupt Control Register */#define DCCR 0x1a /* Daisy Chain Control Register */#define MISR 0x1c /* Misc Interrupt status Register */#define SICR 0x1e /* status Interrupt Control Register */#define RDR 0x20 /* Receive Data Register */#define RMR 0x22 /* Receive mode Register */#define RCSR 0x24 /* Receive Command/status Register */#define RICR 0x26 /* Receive Interrupt Control Register */#define RSR 0x28 /* Receive Sync Register */#define RCLR 0x2a /* Receive count Limit Register */#define RCCR 0x2c /* Receive Character count Register */#define TC0R 0x2e /* Time Constant 0 Register */#define TDR 0x30 /* Transmit Data Register */#define TMR 0x32 /* Transmit mode Register */#define TCSR 0x34 /* Transmit Command/status Register */#define TICR 0x36 /* Transmit Interrupt Control Register */#define TSR 0x38 /* Transmit Sync Register */#define TCLR 0x3a /* Transmit count Limit Register */#define TCCR 0x3c /* Transmit Character count Register */#define TC1R 0x3e /* Time Constant 1 Register *//* * MACRO DEFINITIONS FOR DMA REGISTERS */#define DCR 0x06 /* DMA Control Register (shared) */#define DACR 0x08 /* DMA Array count Register (shared) */#define BDCR 0x12 /* Burst/Dwell Control Register (shared) */#define DIVR 0x14 /* DMA Interrupt Vector Register (shared) */ #define DICR 0x18 /* DMA Interrupt Control Register (shared) */#define CDIR 0x1a /* Clear DMA Interrupt Register (shared) */#define SDIR 0x1c /* Set DMA Interrupt Register (shared) */#define TDMR 0x02 /* Transmit DMA mode Register */#define TDIAR 0x1e /* Transmit DMA Interrupt Arm Register */#define TBCR 0x2a /* Transmit Byte count Register */#define TARL 0x2c /* Transmit Address Register (low) */#define TARU 0x2e /* Transmit Address Register (high) */#define NTBCR 0x3a /* Next Transmit Byte count Register */#define NTARL 0x3c /* Next Transmit Address Register (low) */#define NTARU 0x3e /* Next Transmit Address Register (high) */#define RDMR 0x82 /* Receive DMA mode Register (non-shared) */#define RDIAR 0x9e /* Receive DMA Interrupt Arm Register */#define RBCR 0xaa /* Receive Byte count Register */#define RARL 0xac /* Receive Address Register (low) */#define RARU 0xae /* Receive Address Register (high) */#define NRBCR 0xba /* Next Receive Byte count Register */#define NRARL 0xbc /* Next Receive Address Register (low) */#define NRARU 0xbe /* Next Receive Address Register (high) *//* * MACRO DEFINITIONS FOR MODEM STATUS BITS */#define MODEMSTATUS_DTR 0x80#define MODEMSTATUS_DSR 0x40#define MODEMSTATUS_RTS 0x20#define MODEMSTATUS_CTS 0x10#define MODEMSTATUS_RI 0x04#define MODEMSTATUS_DCD 0x01/* * Channel Command/Address Register (CCAR) Command Codes */#define RTCmd_Null 0x0000
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -