mxser.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,381 行 · 第 1/4 页

C
2,381
字号
/*****************************************************************************//* *          mxser.c  -- MOXA Smartio family multiport serial driver. * *      Copyright (C) 1999-2000  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. *//* *    MOXA Smartio Family Serial Driver * *      Copyright (C) 1999,2000  Moxa Technologies Co., LTD. * *      for             : LINUX 2.0.X, 2.2.X, 2.4.X *      date            : 2001/05/01 *      version         : 1.2  *       *    Fixes for C104H/PCI by Tim Hockin <thockin@sun.com> *    Added support for: C102, CI-132, CI-134, CP-132, CP-114, CT-114 cards *                        by Damian Wrobel <dwrobel@ertel.com.pl> * *    Added support for serial card CP104 *			  by James Nelson Provident Solutions <linux-info@provident-solutions.com> */#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/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/pci.h>#include <linux/init.h>#include <asm/system.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/bitops.h>#include <asm/uaccess.h>#define		MXSER_VERSION			"1.2.1"#define		MXSERMAJOR	 	174#define		MXSERCUMAJOR		175#define	MXSER_EVENT_TXLOW	 1#define	MXSER_EVENT_HANGUP	 2#define 	SERIAL_DO_RESTART#define 	MXSER_BOARDS		4	/* Max. boards */#define 	MXSER_PORTS		32	/* Max. ports */#define 	MXSER_PORTS_PER_BOARD	8	/* Max. ports per board */#define 	MXSER_ISR_PASS_LIMIT	256#define		MXSER_ERR_IOADDR	-1#define		MXSER_ERR_IRQ		-2#define		MXSER_ERR_IRQ_CONFLIT	-3#define		MXSER_ERR_VECTOR	-4#define 	SERIAL_TYPE_NORMAL	1#define 	WAKEUP_CHARS		256#define 	UART_MCR_AFE		0x20#define 	UART_LSR_SPECIAL	0x1E#define PORTNO(x)		((x)->index)#define RELEVANT_IFLAG(iflag)	(iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT)/* *    Define the Moxa PCI vendor and device IDs. */#ifndef	PCI_VENDOR_ID_MOXA#define	PCI_VENDOR_ID_MOXA	0x1393#endif#ifndef PCI_DEVICE_ID_C168#define PCI_DEVICE_ID_C168	0x1680#endif#ifndef PCI_DEVICE_ID_C104#define PCI_DEVICE_ID_C104	0x1040#endif#ifndef PCI_DEVICE_ID_CP104#define PCI_DEVICE_ID_CP104	0x1041#endif#ifndef PCI_DEVICE_ID_CP132#define PCI_DEVICE_ID_CP132	0x1320#endif#ifndef PCI_DEVICE_ID_CP114#define PCI_DEVICE_ID_CP114	0x1141#endif#ifndef PCI_DEVICE_ID_CT114#define PCI_DEVICE_ID_CT114	0x1140#endif#define C168_ASIC_ID    1#define C104_ASIC_ID    2#define CI134_ASIC_ID   3#define CI132_ASIC_ID   4#define CI104J_ASIC_ID  5#define C102_ASIC_ID	0xBenum {	MXSER_BOARD_C168_ISA = 0,	MXSER_BOARD_C104_ISA,	MXSER_BOARD_CI104J,	MXSER_BOARD_C168_PCI,	MXSER_BOARD_C104_PCI,	MXSER_BOARD_CP104_PCI,	MXSER_BOARD_C102_ISA,	MXSER_BOARD_CI132,	MXSER_BOARD_CI134,	MXSER_BOARD_CP132_PCI,	MXSER_BOARD_CP114_PCI,	MXSER_BOARD_CT114_PCI};static char *mxser_brdname[] ={	"C168 series",	"C104 series",	"CI-104J series",	"C168H/PCI series",	"C104H/PCI series",	"CP104/PCI series",	"C102 series",	"CI-132 series",	"CI-134 series",	"CP-132 series",	"CP-114 series",	"CT-114 series"};static int mxser_numports[] ={	8,	4,	4,	8,	4,	4,	2,	2,	4,	2,	4,	4};/* *    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)#ifdef CONFIG_PCIstatic struct pci_device_id mxser_pcibrds[] = {	{ PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_C168, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 	  MXSER_BOARD_C168_PCI },	{ PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_C104, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 	  MXSER_BOARD_C104_PCI },	{ PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_CP104, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 	  MXSER_BOARD_CP104_PCI },	{ PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_CP132, PCI_ANY_ID, PCI_ANY_ID, 0, 0,	  MXSER_BOARD_CP132_PCI },	{ PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_CP114, PCI_ANY_ID, PCI_ANY_ID, 0, 0,	  MXSER_BOARD_CP114_PCI },	{ PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_CT114, PCI_ANY_ID, PCI_ANY_ID, 0, 0,	  MXSER_BOARD_CT114_PCI },	{ 0 }};MODULE_DEVICE_TABLE(pci, mxser_pcibrds);#endif /* CONFIG_PCI */static int ioaddr[MXSER_BOARDS];static int ttymajor = MXSERMAJOR;static int verbose;/* Variables for insmod */MODULE_AUTHOR("William Chen");MODULE_DESCRIPTION("MOXA Smartio Family Multiport Board Device Driver");MODULE_LICENSE("GPL");MODULE_PARM(ioaddr, "1-4i");MODULE_PARM(ttymajor, "i");MODULE_PARM(verbose, "i");struct mxser_hwconf {	int board_type;	int ports;	int irq;	int vector;	int vector_mask;	int uart_type;	int ioaddr[MXSER_PORTS_PER_BOARD];	int baud_base[MXSER_PORTS_PER_BOARD];	struct pci_dev *pdev;};struct mxser_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 */	unsigned char *xmit_buf;	int xmit_head;	int xmit_tail;	int xmit_cnt;	struct work_struct tqueue;	int cflag;	wait_queue_head_t open_wait;	wait_queue_head_t close_wait;	wait_queue_head_t delta_msr_wait;	struct async_icount icount;	/* kernel counters for the 4 input interrupts */};struct mxser_log {	int tick;	int rxcnt[MXSER_PORTS];	int txcnt[MXSER_PORTS];};struct mxser_mstatus {	tcflag_t cflag;	int cts;	int dsr;	int ri;	int dcd;};static struct mxser_mstatus GMStatus[MXSER_PORTS];static int mxserBoardCAP[MXSER_BOARDS] ={	0, 0, 0, 0       /*  0x180, 0x280, 0x200, 0x320   */};static struct tty_driver *mxvar_sdriver;static struct mxser_struct mxvar_table[MXSER_PORTS];static struct mxser_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. */static unsigned char *mxvar_tmp_buf;static struct semaphore mxvar_tmp_buf_sem;/* * 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 mxser_hwconf mxsercfg[MXSER_BOARDS];/* * static functions: */static void mxser_getcfg(int board, struct mxser_hwconf *hwconf);static int mxser_get_ISA_conf(int, struct mxser_hwconf *);static void mxser_do_softint(void *);static int mxser_open(struct tty_struct *, struct file *);static void mxser_close(struct tty_struct *, struct file *);static int mxser_write(struct tty_struct *, int, const unsigned char *, int);static int mxser_write_room(struct tty_struct *);static void mxser_flush_buffer(struct tty_struct *);static int mxser_chars_in_buffer(struct tty_struct *);static void mxser_flush_chars(struct tty_struct *);static void mxser_put_char(struct tty_struct *, unsigned char);static int mxser_ioctl(struct tty_struct *, struct file *, uint, ulong);static int mxser_ioctl_special(unsigned int, unsigned long);static void mxser_throttle(struct tty_struct *);static void mxser_unthrottle(struct tty_struct *);static void mxser_set_termios(struct tty_struct *, struct termios *);static void mxser_stop(struct tty_struct *);static void mxser_start(struct tty_struct *);static void mxser_hangup(struct tty_struct *);static inline void mxser_receive_chars(struct mxser_struct *, int *);static inline void mxser_transmit_chars(struct mxser_struct *);static inline void mxser_check_modem_status(struct mxser_struct *, int);static irqreturn_t mxser_interrupt(int, void *, struct pt_regs *);static int mxser_block_til_ready(struct tty_struct *, struct file *, struct mxser_struct *);static int mxser_startup(struct mxser_struct *);static void mxser_shutdown(struct mxser_struct *);static int mxser_change_speed(struct mxser_struct *, struct termios *old_termios);static int mxser_get_serial_info(struct mxser_struct *, struct serial_struct __user *);static int mxser_set_serial_info(struct mxser_struct *, struct serial_struct __user *);static int mxser_get_lsr_info(struct mxser_struct *, unsigned int __user *);static void mxser_send_break(struct mxser_struct *, int);static int mxser_tiocmget(struct tty_struct *, struct file *);static int mxser_tiocmset(struct tty_struct *, struct file *, unsigned int, unsigned int);/* * The MOXA C168/C104 serial driver boot-time initialization code! */static void __exit mxser_module_exit(void){	int i, err = 0;	if (verbose)		printk("Unloading module mxser ...\n");	if ((err |= tty_unregister_driver(mxvar_sdriver)))		printk("Couldn't unregister MOXA Smartio family serial driver\n");	put_tty_driver(mxvar_sdriver);	for (i = 0; i < MXSER_BOARDS; i++) {		if (mxsercfg[i].board_type == -1)			continue;		else {			free_irq(mxsercfg[i].irq, &mxvar_table[i * MXSER_PORTS_PER_BOARD]);		}	}	if (verbose)		printk("Done.\n");}int mxser_initbrd(int board, struct mxser_hwconf *hwconf){	struct mxser_struct *info;	unsigned long flags;	int retval;	int i, n;	init_MUTEX(&mxvar_tmp_buf_sem);		n = board * MXSER_PORTS_PER_BOARD;	info = &mxvar_table[n];	for (i = 0; i < hwconf->ports; i++, n++, info++) {		if (verbose) {			printk("        ttyM%d/cum%d at 0x%04x ", n, n, hwconf->ioaddr[i]);			if (hwconf->baud_base[i] == 115200)				printk(" max. baud rate up to 115200 bps.\n");			else				printk(" max. baud rate up to 921600 bps.\n");		}		info->port = n;		info->base = hwconf->ioaddr[i];		info->irq = hwconf->irq;		info->vector = hwconf->vector;		info->vectormask = hwconf->vector_mask;		info->rx_trigger = 14;		info->baud_base = hwconf->baud_base[i];		info->flags = ASYNC_SHARE_IRQ;		info->type = hwconf->uart_type;		if ((info->type == PORT_16450) || (info->type == PORT_8250))			info->xmit_fifo_size = 1;		else			info->xmit_fifo_size = 16;		info->custom_divisor = hwconf->baud_base[i] * 16;		info->close_delay = 5 * HZ / 10;		info->closing_wait = 30 * HZ;		INIT_WORK(&info->tqueue, mxser_do_softint, info);		info->cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;		init_waitqueue_head(&info->open_wait);		init_waitqueue_head(&info->close_wait);		init_waitqueue_head(&info->delta_msr_wait);	}	/*	 * Allocate the IRQ if necessary	 */	save_flags(flags);	n = board * MXSER_PORTS_PER_BOARD;	info = &mxvar_table[n];	cli();	retval = request_irq(hwconf->irq, mxser_interrupt, IRQ_T(info),			     "mxser", info);	if (retval) {		restore_flags(flags);		printk("Board %d: %s", board, mxser_brdname[hwconf->board_type]);		printk("  Request irq fail,IRQ (%d) may be conflit with another device.\n", info->irq);		return (retval);	}	restore_flags(flags);	return 0;}static void mxser_getcfg(int board, struct mxser_hwconf *hwconf){	mxsercfg[board] = *hwconf;}#ifdef CONFIG_PCIstatic int mxser_get_PCI_conf(struct pci_dev *pdev, int board_type, struct mxser_hwconf *hwconf){	int i;	unsigned int ioaddress;	hwconf->board_type = board_type;	hwconf->ports = mxser_numports[board_type];	ioaddress = pci_resource_start (pdev, 2);	for (i = 0; i < hwconf->ports; i++)		hwconf->ioaddr[i] = ioaddress + 8 * i;	ioaddress = pci_resource_start (pdev, 3);	hwconf->vector = ioaddress;	hwconf->irq = pdev->irq;	hwconf->uart_type = PORT_16550A;	hwconf->vector_mask = 0;	for (i = 0; i < hwconf->ports; i++) {		hwconf->vector_mask |= (1 << i);		hwconf->baud_base[i] = 921600;	}	return (0);}#endif /* CONFIG_PCI */static struct tty_operations mxser_ops = {	.open = mxser_open,	.close = mxser_close,	.write = mxser_write,	.put_char = mxser_put_char,	.flush_chars = mxser_flush_chars,	.write_room = mxser_write_room,	.chars_in_buffer = mxser_chars_in_buffer,	.flush_buffer = mxser_flush_buffer,	.ioctl = mxser_ioctl,	.throttle = mxser_throttle,	.unthrottle = mxser_unthrottle,	.set_termios = mxser_set_termios,	.stop = mxser_stop,	.start = mxser_start,	.hangup = mxser_hangup,	.tiocmget = mxser_tiocmget,	.tiocmset = mxser_tiocmset,};static int __init mxser_module_init(void){	int i, m, retval, b;	struct mxser_hwconf hwconf;	mxvar_sdriver = alloc_tty_driver(MXSER_PORTS + 1);	if (!mxvar_sdriver)		return -ENOMEM;	printk("MOXA Smartio family driver version %s\n", MXSER_VERSION);	/* Initialize the tty_driver structure */	mxvar_sdriver->owner = THIS_MODULE;	mxvar_sdriver->name = "ttyM";	mxvar_sdriver->devfs_name = "tts/M";	mxvar_sdriver->major = ttymajor;	mxvar_sdriver->minor_start = 0;	mxvar_sdriver->type = TTY_DRIVER_TYPE_SERIAL;	mxvar_sdriver->subtype = SERIAL_TYPE_NORMAL;	mxvar_sdriver->init_termios = tty_std_termios;	mxvar_sdriver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;	mxvar_sdriver->flags = TTY_DRIVER_REAL_RAW;	tty_set_operations(mxvar_sdriver, &mxser_ops);	printk("Tty devices major number = %d\n", ttymajor);	mxvar_diagflag = 0;	memset(mxvar_table, 0, MXSER_PORTS * sizeof(struct mxser_struct));	memset(&mxvar_log, 0, sizeof(struct mxser_log));	m = 0;	/* Start finding ISA boards here */	for (b = 0; b < MXSER_BOARDS && m < MXSER_BOARDS; b++) {		int cap;		if (!(cap = mxserBoardCAP[b]))			continue;		retval = mxser_get_ISA_conf(cap, &hwconf);		if (retval != 0)			printk("Found MOXA %s board (CAP=0x%x)\n",			       mxser_brdname[hwconf.board_type],			       ioaddr[b]);		if (retval <= 0) {			if (retval == MXSER_ERR_IRQ)				printk("Invalid interrupt number,board not configured\n");			else if (retval == MXSER_ERR_IRQ_CONFLIT)				printk("Invalid interrupt number,board not configured\n");			else if (retval == MXSER_ERR_VECTOR)				printk("Invalid interrupt vector,board not configured\n");			else if (retval == MXSER_ERR_IOADDR)				printk("Invalid I/O address,board not configured\n");			continue;		}		hwconf.pdev = NULL;		if (mxser_initbrd(m, &hwconf) < 0)			continue;		mxser_getcfg(m, &hwconf);		m++;	}	/* Start finding ISA boards from module arg */	for (b = 0; b < MXSER_BOARDS && m < MXSER_BOARDS; b++) {		int cap;		if (!(cap = ioaddr[b]))			continue;		retval = mxser_get_ISA_conf(cap, &hwconf);		if (retval != 0)			printk("Found MOXA %s board (CAP=0x%x)\n",			       mxser_brdname[hwconf.board_type],			       ioaddr[b]);		if (retval <= 0) {			if (retval == MXSER_ERR_IRQ)				printk("Invalid interrupt number,board not configured\n");			else if (retval == MXSER_ERR_IRQ_CONFLIT)				printk("Invalid interrupt number,board not configured\n");			else if (retval == MXSER_ERR_VECTOR)				printk("Invalid interrupt vector,board not configured\n");			else if (retval == MXSER_ERR_IOADDR)				printk("Invalid I/O address,board not configured\n");

⌨️ 快捷键说明

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