?? mxpcdrv.c
字號:
/* * mxpcdrv.c -- MOXA PC104 Communication Module Linux driver. * * Copyright (C) 1999-2007 Moxa Technologies (support@moxa.com.tw). * * This code is loosely based on the Linux serial driver, written by * Linus Torvalds, Theodore T'so and others. * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * * Original release 03/20/03 * * 03/20/03 Support MOXA PC104 Communication Module. * */#ifdef MODVERSIONS#ifndef MODULE#define MODULE#endif#endif#include <linux/version.h>#define VERSION_CODE(ver,rel,seq) ((ver << 16) | (rel << 8) | seq)#ifdef MODULE#if (LINUX_VERSION_CODE < VERSION_CODE(2,6,18))#include <linux/config.h>#endif#ifdef MODVERSIONS#include <linux/modversions.h>#endif#include <linux/module.h>#else#define MOD_INC_USE_COUNT#define MOD_DEC_USE_COUNT#endif#include <linux/autoconf.h>#include <linux/errno.h>#include <linux/signal.h>#include <linux/sched.h>#include <linux/timer.h>#include <linux/interrupt.h>#include <linux/tty.h>#include <linux/tty_flip.h>#include <linux/serial.h>#include <linux/serial_reg.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/smp_lock.h>#include <linux/delay.h>#include <asm/system.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/segment.h>#include <asm/bitops.h>#include "mxpcdrv.h"#define MXPCDRV_VERSION "1.2"#define MXPCDRVMAJOR 34#define MXPCDRVCUMAJOR 41 #if (LINUX_VERSION_CODE < VERSION_CODE(2,1,0))#define copy_from_user memcpy_fromfs#define copy_to_user memcpy_tofs#define put_to_user(arg1, arg2) put_fs_long(arg1, (unsigned long *)arg2)#define get_from_user(arg1, arg2) arg1 = get_fs_long((unsigned long *)arg2)#define schedule_timeout(x) {current->timeout = jiffies + (x); schedule();}#define signal_pending(x) ((x)->signal & ~(x)->blocked)#else#include <asm/uaccess.h>#define put_to_user(arg1, arg2) put_user(arg1, (unsigned long *)arg2)#define get_from_user(arg1, arg2) get_user(arg1, (unsigned int *)arg2)#endif#define MXPCDRV_EVENT_TXLOW 1#define MXPCDRV_EVENT_HANGUP 2#define SERIAL_DO_RESTART#define MXPCDRV_BOARDS 4 /* Max. boards */#define MXPCDRV_PORTS 32 /* Max. ports */#define MXPCDRV_PORTS_PER_BOARD 8 /* Max. ports per board*/#define MXPCDRV_ISR_PASS_LIMIT 99999L#define MXPCDRV_BOARD_INDEX 4#define MXPCDRV_ERR_IOADDR -1#define MXPCDRV_ERR_IRQ -2#define MXPCDRV_ERR_IRQ_CONFLIT -3#define MXPCDRV_ERR_VECTOR -4#define SERIAL_TYPE_NORMAL 1#define SERIAL_TYPE_CALLOUT 2#define WAKEUP_CHARS 256#define UART_MCR_AFE 0x20#define UART_LSR_SPECIAL 0x1E#define UART_CLK_DIV 921600#define MX_LOCK_INIT() unsigned long flags=0#define MX_LOCK(lock) {\ if(!in_interrupt())\ spin_lock_irqsave(lock, flags);\ }#define MX_UNLOCK(lock) {\ if(!in_interrupt())\ spin_unlock_irqrestore(lock, flags);\ }#if (LINUX_VERSION_CODE < VERSION_CODE(2,6,0))#define PORTNO(x) (MINOR((x)->device) - (x)->driver.minor_start)#else#define PORTNO(x) ((x)->index)#endif#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK|IXON|IXOFF))#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT)#ifndef MIN#define MIN(a,b) ((a) < (b) ? (a) : (b))#endif/* * Define the Moxa device IDs. */#define CA104_ID 1#define CA132_ID 2#define CA132I_ID 3#define CA108_ID 4#define CA114_ID 5#define CA134I_ID 6enum { MXPCDRV_BOARD_CA104 = 1, MXPCDRV_BOARD_CA132, MXPCDRV_BOARD_CA132I, MXPCDRV_BOARD_CA108, MXPCDRV_BOARD_CA114, MXPCDRV_BOARD_CA134I};static char *mxpcdrv_brdname[] = { "CA-104 series", "CA-132 series", "CA-132I series", "CA-108 series", "CA-114 series", "CA-134I series"};static int mxpcdrv_numports[] = { 4, // CA104 2, // CA132 2, // CA132I 8, // CA108 4, // CA114 4 // CA134I}; /* * MOXA ioctls */#define MOXA 0x400#define MOXA_GETDATACOUNT (MOXA + 23)#define MOXA_GET_CONF (MOXA + 35)#define MOXA_DIAGNOSE (MOXA + 50)#define MOXA_CHKPORTENABLE (MOXA + 60)#define MOXA_HighSpeedOn (MOXA + 61)#define MOXA_GET_MAJOR (MOXA + 63)#define MOXA_GET_CUMAJOR (MOXA + 64)#define MOXA_GETMSTATUS (MOXA + 65)#define MOXA_SET_SPECIAL_BAUD_RATE (MOXA + 66)#define MOXA_GET_SPECIAL_BAUD_RATE (MOXA + 67)typedef struct _moxa_pci_info { unsigned short busNum; unsigned short devNum;} moxa_pci_info;static int ioaddr[MXPCDRV_BOARDS]={0,0,0,0};static int iovect[MXPCDRV_BOARDS]={0,0,0,0};static int irq[MXPCDRV_BOARDS]={0,0,0,0};static int ttymajor=MXPCDRVMAJOR;static int calloutmajor=MXPCDRVCUMAJOR;static int verbose=0;#ifdef MODULE/* Variables for insmod */# if (LINUX_VERSION_CODE > VERSION_CODE(2,1,11))MODULE_AUTHOR("Eric Lo");MODULE_DESCRIPTION("MOXA PC104 Communication Module Device Driver");#if defined SP2 || (LINUX_VERSION_CODE > VERSION_CODE(2,6,9))int mx_ioaddr_array_num;int mx_iovect_array_num;int mx_irq_array_num;module_param_array(ioaddr, int, &mx_ioaddr_array_num, 0);module_param_array(iovect, int, &mx_iovect_array_num, 0);module_param_array(irq, int, &mx_irq_array_num, 0);module_param(ttymajor, int, 0);module_param(calloutmajor, int, 0);module_param(verbose, int, 0);#elseMODULE_PARM(ioaddr, "1-4i");MODULE_PARM(iovect, "1-4i");MODULE_PARM(irq, "1-4i");MODULE_PARM(ttymajor, "i");MODULE_PARM(calloutmajor, "i");MODULE_PARM(verbose, "i");#endif#ifdef MODULE_LICENSEMODULE_LICENSE("GPL");#endif# endif#endif /* MODULE */struct mxpcdrv_hwconf { int board_type; int ports; int irq; int vector; int vector_mask; int uart_type; int ioaddr[MXPCDRV_PORTS_PER_BOARD]; int baud_base[MXPCDRV_PORTS_PER_BOARD]; moxa_pci_info pciInfo; int IsMoxaMustChipFlag; // add by Victor Yu. 08-30-2002 int MaxCanSetBaudRate[MXPCDRV_PORTS_PER_BOARD]; // add by Victor Yu. 09-04-2002};struct mxpcdrv_struct { int port; int base; /* port base address */ int irq; /* port using irq no. */ int vector; /* port irq vector */ int vectormask; /* port vector mask */ int rx_trigger; /* Rx fifo trigger level */ int baud_base; /* max. speed */ int flags; /* defined in tty.h */ int type; /* UART type */ struct tty_struct * tty; int read_status_mask; int ignore_status_mask; int xmit_fifo_size; int custom_divisor; int x_char; /* xon/xoff character */ int close_delay; unsigned short closing_wait; int IER; /* Interrupt Enable Register */ int MCR; /* Modem control register */ unsigned long event; int count; /* # of fd on device */ int blocked_open; /* # of blocked opens */ long session; /* Session of opening process */ long pgrp; /* pgrp of opening process */ unsigned char *xmit_buf; int xmit_head; int xmit_tail; int xmit_cnt;#if (LINUX_VERSION_CODE < VERSION_CODE(2,6,0)) struct tq_struct tqueue;#else struct work_struct tqueue;#endif#if (LINUX_VERSION_CODE > VERSION_CODE(2,6,19)) struct ktermios normal_termios; struct ktermios callout_termios;#else struct termios normal_termios; struct termios callout_termios;#endif#if (LINUX_VERSION_CODE < VERSION_CODE(2,4,0)) struct wait_queue *open_wait; struct wait_queue *close_wait; struct wait_queue *delta_msr_wait;#else wait_queue_head_t open_wait; wait_queue_head_t close_wait; wait_queue_head_t delta_msr_wait;#endif struct async_icount icount; /* kernel counters for the 4 input interrupts */ int timeout; int IsMoxaMustChipFlag; // add by Victor Yu. 08-30-2002 int MaxCanSetBaudRate; // add by Victor Yu. 09-04-2002 unsigned char ldisc_stop_rx; spinlock_t slock; int cur_baud;};struct mxpcdrv_log { int tick; int rxcnt[MXPCDRV_PORTS]; int txcnt[MXPCDRV_PORTS];};struct mxpcdrv_mstatus{ tcflag_t cflag; int cts; int dsr; int ri; int dcd;};static struct mxpcdrv_mstatus GMStatus[MXPCDRV_PORTS];static int mxpcdrvBoardIO[MXPCDRV_BOARDS] = { 0,0,0,0 /* 0x180, 0x280, 0x200, 0x320 */};static int mxpcdrvBoardIRQ[MXPCDRV_BOARDS] = { 0,0,0,0 };static int mxpcdrvBoardVECT[MXPCDRV_BOARDS] = { 0,0,0,0 };#if (LINUX_VERSION_CODE < VERSION_CODE(2,6,0))static struct tty_driver mxvar_sdriver;static struct tty_driver mxvar_cdriver;#elsestatic struct tty_driver *mxvar_sdriver;#endif#if (LINUX_VERSION_CODE < VERSION_CODE(2,6,0))static int mxvar_refcount;#endif//static struct tty_driver mxvar_sdriver, mxvar_cdriver;//static int mxvar_refcount;static struct mxpcdrv_struct mxvar_table[MXPCDRV_PORTS];static struct tty_struct * mxvar_tty[MXPCDRV_PORTS+1];#if (LINUX_VERSION_CODE > VERSION_CODE(2,6,19))static struct ktermios * mxvar_termios[MXPCDRV_PORTS+1];static struct ktermios * mxvar_termios_locked[MXPCDRV_PORTS+1];#elsestatic struct termios * mxvar_termios[MXPCDRV_PORTS+1];static struct termios * mxvar_termios_locked[MXPCDRV_PORTS+1];#endifstatic struct mxpcdrv_log mxvar_log;static int mxvar_diagflag;/* * mxvar_tmp_buf is used as a temporary buffer by serial_write. We need * to lock it in case the memcpy_fromfs blocks while swapping in a page, * and some other program tries to do a serial write at the same time. * Since the lock will only come under contention when the system is * swapping and available memory is low, it makes sense to share one * buffer across all the serial ports, since it significantly saves * memory if large numbers of serial ports are open. */#if (LINUX_VERSION_CODE >= VERSION_CODE(2,4,0))static unsigned char * mxvar_tmp_buf;static struct semaphore mxvar_tmp_buf_sem;#elsestatic unsigned char * mxvar_tmp_buf = 0;static struct semaphore mxvar_tmp_buf_sem = MUTEX;#endif/* * This is used to figure out the divisor speeds and the timeouts */static int mxvar_baud_table[] = { 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600, 0 }; struct mxpcdrv_hwconf mxpcdrvcfg[MXPCDRV_BOARDS];/* * static functions: */#ifdef MODULEint init_module(void);void cleanup_module(void);#endifstatic void mxpcdrv_getcfg(int board,struct mxpcdrv_hwconf *hwconf);int mxpcdrv_init(void);static int mxpcdrv_get_ISA_conf(int, int, struct mxpcdrv_hwconf *, int);#if (LINUX_VERSION_CODE > VERSION_CODE(2,6,19))static void mxpcdrv_do_softint(struct work_struct *work);#elsestatic void mxpcdrv_do_softint(void *);#endifstatic int mxpcdrv_open(struct tty_struct *, struct file *);static void mxpcdrv_close(struct tty_struct *, struct file *);#if (LINUX_VERSION_CODE < VERSION_CODE(2,6,10))static int mxpcdrv_write(struct tty_struct *, int, const unsigned char *, int);#elsestatic int mxpcdrv_write(struct tty_struct *, const unsigned char *, int);#endifstatic int mxpcdrv_write_room(struct tty_struct *);static void mxpcdrv_flush_buffer(struct tty_struct *);static int mxpcdrv_chars_in_buffer(struct tty_struct *);static void mxpcdrv_flush_chars(struct tty_struct *);static void mxpcdrv_put_char(struct tty_struct *, unsigned char);static int mxpcdrv_ioctl(struct tty_struct *, struct file *, uint, ulong);static int mxpcdrv_ioctl_special(unsigned int, unsigned long);static void mxpcdrv_throttle(struct tty_struct *);static void mxpcdrv_unthrottle(struct tty_struct *);#if (LINUX_VERSION_CODE > VERSION_CODE(2,6,19))static void mxpcdrv_set_termios(struct tty_struct *, struct ktermios *);#elsestatic void mxpcdrv_set_termios(struct tty_struct *, struct termios *);#endifstatic void mxpcdrv_stop(struct tty_struct *);static void mxpcdrv_start(struct tty_struct *);static void mxpcdrv_hangup(struct tty_struct *);#if (LINUX_VERSION_CODE > VERSION_CODE(2,6,19))static irqreturn_t mxpcdrv_interrupt(int irq, void *dev_id);#elsestatic IRQ_RET mxpcdrv_interrupt(int, void *, struct pt_regs *);#endifstatic void mxpcdrv_receive_chars(struct mxpcdrv_struct *, int *);static void mxpcdrv_transmit_chars(struct mxpcdrv_struct *);static void mxpcdrv_check_modem_status(struct mxpcdrv_struct *, int);static int mxpcdrv_block_til_ready(struct tty_struct *, struct file *, struct mxpcdrv_struct *);static int mxpcdrv_startup(struct mxpcdrv_struct *);static void mxpcdrv_shutdown(struct mxpcdrv_struct *);#if (LINUX_VERSION_CODE > VERSION_CODE(2,6,19))static int mxpcdrv_change_speed(struct mxpcdrv_struct *, struct ktermios *old_termios);#elsestatic int mxpcdrv_change_speed(struct mxpcdrv_struct *, struct termios *old_termios);#endifstatic int mxpcdrv_get_serial_info(struct mxpcdrv_struct *, struct serial_struct *);static int mxpcdrv_set_serial_info(struct mxpcdrv_struct *, struct serial_struct *);static int mxpcdrv_get_lsr_info(struct mxpcdrv_struct *, unsigned int *);static void mxpcdrv_send_break(struct mxpcdrv_struct *, int);#if (LINUX_VERSION_CODE >= VERSION_CODE(2,6,0))static int mxpcdrv_tiocmget(struct tty_struct *, struct file *);static int mxpcdrv_tiocmset(struct tty_struct *, struct file *, unsigned int, unsigned int);#elsestatic int mxpcdrv_get_modem_info(struct mxpcdrv_struct *, unsigned int *);static int mxpcdrv_set_modem_info(struct mxpcdrv_struct *, unsigned int, unsigned int *);#endif#if (LINUX_VERSION_CODE >= VERSION_CODE(2,1,0))static void mxpcdrv_wait_until_sent(struct tty_struct *tty, int timeout);#endifstatic void mxpcdrv_startrx(struct tty_struct * tty);static void mxpcdrv_stoprx(struct tty_struct * tty);static void mxpcdrv_set_special_baudrate(struct mxpcdrv_struct * info, int baud);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -