📄 synclink_gt.c
字号:
/* * $Id: synclink_gt.c,v 4.50 2007/07/25 19:29:25 paulkf Exp $ * * Device driver for Microgate SyncLink GT serial adapters. * * written by Paul Fulghum for Microgate Corporation * paulkf@microgate.com * * Microgate and SyncLink are trademarks of Microgate Corporation * * This code is released under the GNU General Public License (GPL) * * 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. *//* * DEBUG OUTPUT DEFINITIONS * * uncomment lines below to enable specific types of debug output * * DBGINFO information - most verbose output * DBGERR serious errors * DBGBH bottom half service routine debugging * DBGISR interrupt service routine debugging * DBGDATA output receive and transmit data * DBGTBUF output transmit DMA buffers and registers * DBGRBUF output receive DMA buffers and registers */#define DBGINFO(fmt) if (debug_level >= DEBUG_LEVEL_INFO) printk fmt#define DBGERR(fmt) if (debug_level >= DEBUG_LEVEL_ERROR) printk fmt#define DBGBH(fmt) if (debug_level >= DEBUG_LEVEL_BH) printk fmt#define DBGISR(fmt) if (debug_level >= DEBUG_LEVEL_ISR) printk fmt#define DBGDATA(info, buf, size, label) if (debug_level >= DEBUG_LEVEL_DATA) trace_block((info), (buf), (size), (label))//#define DBGTBUF(info) dump_tbufs(info)//#define DBGRBUF(info) dump_rbufs(info)#include <linux/module.h>#include <linux/version.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/slab.h>#include <linux/netdevice.h>#include <linux/vmalloc.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/ioctl.h>#include <linux/termios.h>#include <linux/bitops.h>#include <linux/workqueue.h>#include <linux/hdlc.h>#include <asm/system.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/dma.h>#include <asm/types.h>#include <asm/uaccess.h>#include "linux/synclink.h"#if defined(CONFIG_HDLC) || (defined(CONFIG_HDLC_MODULE) && defined(CONFIG_SYNCLINK_GT_MODULE))#define SYNCLINK_GENERIC_HDLC 1#else#define SYNCLINK_GENERIC_HDLC 0#endif/* * module identification */static char *driver_name = "SyncLink GT";static char *driver_version = "$Revision: 4.50 $";static char *tty_driver_name = "synclink_gt";static char *tty_dev_prefix = "ttySLG";MODULE_LICENSE("GPL");#define MGSL_MAGIC 0x5401#define MAX_DEVICES 32static struct pci_device_id pci_table[] = { {PCI_VENDOR_ID_MICROGATE, SYNCLINK_GT_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, {PCI_VENDOR_ID_MICROGATE, SYNCLINK_GT2_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, {PCI_VENDOR_ID_MICROGATE, SYNCLINK_GT4_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, {PCI_VENDOR_ID_MICROGATE, SYNCLINK_AC_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, {0,}, /* terminate list */};MODULE_DEVICE_TABLE(pci, pci_table);static int init_one(struct pci_dev *dev,const struct pci_device_id *ent);static void remove_one(struct pci_dev *dev);static struct pci_driver pci_driver = { .name = "synclink_gt", .id_table = pci_table, .probe = init_one, .remove = __devexit_p(remove_one),};static int pci_registered;/* * module configuration and status */static struct slgt_info *slgt_device_list;static int slgt_device_count;static int ttymajor;static int debug_level;static int maxframe[MAX_DEVICES];static int dosyncppp[MAX_DEVICES];module_param(ttymajor, int, 0);module_param(debug_level, int, 0);module_param_array(maxframe, int, NULL, 0);module_param_array(dosyncppp, int, NULL, 0);MODULE_PARM_DESC(ttymajor, "TTY major device number override: 0=auto assigned");MODULE_PARM_DESC(debug_level, "Debug syslog output: 0=disabled, 1 to 5=increasing detail");MODULE_PARM_DESC(maxframe, "Maximum frame size used by device (4096 to 65535)");MODULE_PARM_DESC(dosyncppp, "Enable synchronous net device, 0=disable 1=enable");/* * tty support and callbacks */static struct tty_driver *serial_driver;static int open(struct tty_struct *tty, struct file * filp);static void close(struct tty_struct *tty, struct file * filp);static void hangup(struct tty_struct *tty);static void set_termios(struct tty_struct *tty, struct ktermios *old_termios);static int write(struct tty_struct *tty, const unsigned char *buf, int count);static void put_char(struct tty_struct *tty, unsigned char ch);static void send_xchar(struct tty_struct *tty, char ch);static void wait_until_sent(struct tty_struct *tty, int timeout);static int write_room(struct tty_struct *tty);static void flush_chars(struct tty_struct *tty);static void flush_buffer(struct tty_struct *tty);static void tx_hold(struct tty_struct *tty);static void tx_release(struct tty_struct *tty);static int ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg);static int read_proc(char *page, char **start, off_t off, int count,int *eof, void *data);static int chars_in_buffer(struct tty_struct *tty);static void throttle(struct tty_struct * tty);static void unthrottle(struct tty_struct * tty);static void set_break(struct tty_struct *tty, int break_state);/* * generic HDLC support and callbacks */#if SYNCLINK_GENERIC_HDLC#define dev_to_port(D) (dev_to_hdlc(D)->priv)static void hdlcdev_tx_done(struct slgt_info *info);static void hdlcdev_rx(struct slgt_info *info, char *buf, int size);static int hdlcdev_init(struct slgt_info *info);static void hdlcdev_exit(struct slgt_info *info);#endif/* * device specific structures, macros and functions */#define SLGT_MAX_PORTS 4#define SLGT_REG_SIZE 256/* * conditional wait facility */struct cond_wait { struct cond_wait *next; wait_queue_head_t q; wait_queue_t wait; unsigned int data;};static void init_cond_wait(struct cond_wait *w, unsigned int data);static void add_cond_wait(struct cond_wait **head, struct cond_wait *w);static void remove_cond_wait(struct cond_wait **head, struct cond_wait *w);static void flush_cond_wait(struct cond_wait **head);/* * DMA buffer descriptor and access macros */struct slgt_desc{ __le16 count; __le16 status; __le32 pbuf; /* physical address of data buffer */ __le32 next; /* physical address of next descriptor */ /* driver book keeping */ char *buf; /* virtual address of data buffer */ unsigned int pdesc; /* physical address of this descriptor */ dma_addr_t buf_dma_addr;};#define set_desc_buffer(a,b) (a).pbuf = cpu_to_le32((unsigned int)(b))#define set_desc_next(a,b) (a).next = cpu_to_le32((unsigned int)(b))#define set_desc_count(a,b)(a).count = cpu_to_le16((unsigned short)(b))#define set_desc_eof(a,b) (a).status = cpu_to_le16((b) ? (le16_to_cpu((a).status) | BIT0) : (le16_to_cpu((a).status) & ~BIT0))#define desc_count(a) (le16_to_cpu((a).count))#define desc_status(a) (le16_to_cpu((a).status))#define desc_complete(a) (le16_to_cpu((a).status) & BIT15)#define desc_eof(a) (le16_to_cpu((a).status) & BIT2)#define desc_crc_error(a) (le16_to_cpu((a).status) & BIT1)#define desc_abort(a) (le16_to_cpu((a).status) & BIT0)#define desc_residue(a) ((le16_to_cpu((a).status) & 0x38) >> 3)struct _input_signal_events { int ri_up; int ri_down; int dsr_up; int dsr_down; int dcd_up; int dcd_down; int cts_up; int cts_down;};/* * device instance data structure */struct slgt_info { void *if_ptr; /* General purpose pointer (used by SPPP) */ struct slgt_info *next_device; /* device list link */ int magic; int flags; char device_name[25]; struct pci_dev *pdev; int port_count; /* count of ports on adapter */ int adapter_num; /* adapter instance number */ int port_num; /* port instance number */ /* array of pointers to port contexts on this adapter */ struct slgt_info *port_array[SLGT_MAX_PORTS]; int count; /* count of opens */ int line; /* tty line instance number */ unsigned short close_delay; unsigned short closing_wait; /* time to wait before closing */ struct mgsl_icount icount; struct tty_struct *tty; int timeout; int x_char; /* xon/xoff character */ int blocked_open; /* # of blocked opens */ unsigned int read_status_mask; unsigned int ignore_status_mask; wait_queue_head_t open_wait; wait_queue_head_t close_wait; wait_queue_head_t status_event_wait_q; wait_queue_head_t event_wait_q; struct timer_list tx_timer; struct timer_list rx_timer; unsigned int gpio_present; struct cond_wait *gpio_wait_q; spinlock_t lock; /* spinlock for synchronizing with ISR */ struct work_struct task; u32 pending_bh; int bh_requested; int bh_running; int isr_overflow; int irq_requested; /* nonzero if IRQ requested */ int irq_occurred; /* for diagnostics use */ /* device configuration */ unsigned int bus_type; unsigned int irq_level; unsigned long irq_flags; unsigned char __iomem * reg_addr; /* memory mapped registers address */ u32 phys_reg_addr; int reg_addr_requested; MGSL_PARAMS params; /* communications parameters */ u32 idle_mode; u32 max_frame_size; /* as set by device config */ unsigned int raw_rx_size; unsigned int if_mode; /* device status */ int rx_enabled; int rx_restart; int tx_enabled; int tx_active; unsigned char signals; /* serial signal states */ int init_error; /* initialization error */ unsigned char *tx_buf; int tx_count; char flag_buf[MAX_ASYNC_BUFFER_SIZE]; char char_buf[MAX_ASYNC_BUFFER_SIZE]; BOOLEAN drop_rts_on_tx_done; struct _input_signal_events input_signal_events; int dcd_chkcount; /* check counts to prevent */ int cts_chkcount; /* too many IRQs if a signal */ int dsr_chkcount; /* is floating */ int ri_chkcount; char *bufs; /* virtual address of DMA buffer lists */ dma_addr_t bufs_dma_addr; /* physical address of buffer descriptors */ unsigned int rbuf_count; struct slgt_desc *rbufs; unsigned int rbuf_current; unsigned int rbuf_index; unsigned int tbuf_count; struct slgt_desc *tbufs; unsigned int tbuf_current; unsigned int tbuf_start; unsigned char *tmp_rbuf; unsigned int tmp_rbuf_count; /* SPPP/Cisco HDLC device parts */ int netcount; int dosyncppp; spinlock_t netlock;#if SYNCLINK_GENERIC_HDLC struct net_device *netdev;#endif};static MGSL_PARAMS default_params = { .mode = MGSL_MODE_HDLC, .loopback = 0, .flags = HDLC_FLAG_UNDERRUN_ABORT15, .encoding = HDLC_ENCODING_NRZI_SPACE, .clock_speed = 0, .addr_filter = 0xff, .crc_type = HDLC_CRC_16_CCITT, .preamble_length = HDLC_PREAMBLE_LENGTH_8BITS, .preamble = HDLC_PREAMBLE_PATTERN_NONE, .data_rate = 9600, .data_bits = 8, .stop_bits = 1, .parity = ASYNC_PARITY_NONE};#define BH_RECEIVE 1#define BH_TRANSMIT 2#define BH_STATUS 4#define IO_PIN_SHUTDOWN_LIMIT 100#define DMABUFSIZE 256#define DESC_LIST_SIZE 4096#define MASK_PARITY BIT1#define MASK_FRAMING BIT0#define MASK_BREAK BIT14#define MASK_OVERRUN BIT4#define GSR 0x00 /* global status */#define JCR 0x04 /* JTAG control */#define IODR 0x08 /* GPIO direction */#define IOER 0x0c /* GPIO interrupt enable */#define IOVR 0x10 /* GPIO value */#define IOSR 0x14 /* GPIO interrupt status */#define TDR 0x80 /* tx data */#define RDR 0x80 /* rx data */#define TCR 0x82 /* tx control */#define TIR 0x84 /* tx idle */#define TPR 0x85 /* tx preamble */#define RCR 0x86 /* rx control */#define VCR 0x88 /* V.24 control */#define CCR 0x89 /* clock control */#define BDR 0x8a /* baud divisor */#define SCR 0x8c /* serial control */#define SSR 0x8e /* serial status */#define RDCSR 0x90 /* rx DMA control/status */#define TDCSR 0x94 /* tx DMA control/status */#define RDDAR 0x98 /* rx DMA descriptor address */#define TDDAR 0x9c /* tx DMA descriptor address */#define RXIDLE BIT14#define RXBREAK BIT14#define IRQ_TXDATA BIT13#define IRQ_TXIDLE BIT12#define IRQ_TXUNDER BIT11 /* HDLC */#define IRQ_RXDATA BIT10#define IRQ_RXIDLE BIT9 /* HDLC */#define IRQ_RXBREAK BIT9 /* async */#define IRQ_RXOVER BIT8#define IRQ_DSR BIT7#define IRQ_CTS BIT6#define IRQ_DCD BIT5#define IRQ_RI BIT4#define IRQ_ALL 0x3ff0#define IRQ_MASTER BIT0#define slgt_irq_on(info, mask) \ wr_reg16((info), SCR, (unsigned short)(rd_reg16((info), SCR) | (mask)))#define slgt_irq_off(info, mask) \ wr_reg16((info), SCR, (unsigned short)(rd_reg16((info), SCR) & ~(mask)))static __u8 rd_reg8(struct slgt_info *info, unsigned int addr);static void wr_reg8(struct slgt_info *info, unsigned int addr, __u8 value);static __u16 rd_reg16(struct slgt_info *info, unsigned int addr);static void wr_reg16(struct slgt_info *info, unsigned int addr, __u16 value);static __u32 rd_reg32(struct slgt_info *info, unsigned int addr);static void wr_reg32(struct slgt_info *info, unsigned int addr, __u32 value);static void msc_set_vcr(struct slgt_info *info);static int startup(struct slgt_info *info);static int block_til_ready(struct tty_struct *tty, struct file * filp,struct slgt_info *info);static void shutdown(struct slgt_info *info);static void program_hw(struct slgt_info *info);static void change_params(struct slgt_info *info);static int register_test(struct slgt_info *info);static int irq_test(struct slgt_info *info);static int loopback_test(struct slgt_info *info);static int adapter_test(struct slgt_info *info);static void reset_adapter(struct slgt_info *info);static void reset_port(struct slgt_info *info);static void async_mode(struct slgt_info *info);static void sync_mode(struct slgt_info *info);static void rx_stop(struct slgt_info *info);static void rx_start(struct slgt_info *info);static void reset_rbufs(struct slgt_info *info);static void free_rbufs(struct slgt_info *info, unsigned int first, unsigned int last);static void rdma_reset(struct slgt_info *info);static int rx_get_frame(struct slgt_info *info);static int rx_get_buf(struct slgt_info *info);static void tx_start(struct slgt_info *info);static void tx_stop(struct slgt_info *info);static void tx_set_idle(struct slgt_info *info);static unsigned int free_tbuf_count(struct slgt_info *info);static void reset_tbufs(struct slgt_info *info);static void tdma_reset(struct slgt_info *info);static void tdma_start(struct slgt_info *info);static void tx_load(struct slgt_info *info, const char *buf, unsigned int count);static void get_signals(struct slgt_info *info);static void set_signals(struct slgt_info *info);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -