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

📄 mxser.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/*****************************************************************************//* *          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 *      date            : 1999/07/22 *      version         : 1.1  *       */#include <linux/config.h>#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/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 <asm/system.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/segment.h>#include <asm/bitops.h>#include <asm/uaccess.h>#define		MXSER_VERSION			"1.1kern"#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 	SERIAL_TYPE_CALLOUT	2#define 	WAKEUP_CHARS		256#define 	UART_MCR_AFE		0x20#define 	UART_LSR_SPECIAL	0x1E#define PORTNO(x)		(MINOR((x)->device) - (x)->driver.minor_start)#define RELEVANT_IFLAG(iflag)	(iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))#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 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#define C168_ASIC_ID    1#define C104_ASIC_ID    2#define CI104J_ASIC_ID  5enum {	MXSER_BOARD_C168_ISA = 0,	MXSER_BOARD_C104_ISA,	MXSER_BOARD_CI104J,	MXSER_BOARD_C168_PCI,	MXSER_BOARD_C104_PCI,};static char *mxser_brdname[] ={	"C168 series",	"C104 series",	"CI-104J series",	"C168H/PCI series",	"C104H/PCI series",};static int mxser_numports[] ={	8,	4,	4,	8,	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)typedef struct {	unsigned short vendor_id;	unsigned short device_id;	unsigned short board_type;} mxser_pciinfo;static mxser_pciinfo mxser_pcibrds[] ={	{PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_C168, MXSER_BOARD_C168_PCI},	{PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_C104, MXSER_BOARD_C104_PCI},};static int ioaddr[MXSER_BOARDS];static int ttymajor = MXSERMAJOR;static int calloutmajor = MXSERCUMAJOR;static int verbose;/* Variables for insmod */MODULE_AUTHOR("William Chen");MODULE_DESCRIPTION("MOXA Smartio Family Multiport Board Device Driver");MODULE_PARM(ioaddr, "1-4i");MODULE_PARM(ttymajor, "i");MODULE_PARM(calloutmajor, "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 */	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;	struct tq_struct tqueue;	struct termios normal_termios;	struct termios callout_termios;	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, mxvar_cdriver;static int mxvar_refcount;static struct mxser_struct mxvar_table[MXSER_PORTS];static struct tty_struct *mxvar_tty[MXSER_PORTS + 1];static struct termios *mxvar_termios[MXSER_PORTS + 1];static struct termios *mxvar_termios_locked[MXSER_PORTS + 1];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: */#ifdef MODULEint init_module(void);void cleanup_module(void);#endifstatic void mxser_getcfg(int board, struct mxser_hwconf *hwconf);int mxser_init(void);static int mxser_get_ISA_conf(int, struct mxser_hwconf *);static int mxser_get_PCI_conf(struct pci_dev *, 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 void mxser_interrupt(int, void *, struct pt_regs *);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 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 *);static int mxser_set_serial_info(struct mxser_struct *, struct serial_struct *);static int mxser_get_lsr_info(struct mxser_struct *, unsigned int *);static void mxser_send_break(struct mxser_struct *, int);static int mxser_get_modem_info(struct mxser_struct *, unsigned int *);static int mxser_set_modem_info(struct mxser_struct *, unsigned int, unsigned int *);/* * The MOXA C168/C104 serial driver boot-time initialization code! */#ifdef MODULEint init_module(void){	int ret;	if (verbose)		printk("Loading module mxser ...\n");	ret = mxser_init();	if (verbose)		printk("Done.\n");	return (ret);}void cleanup_module(void){	int i, err = 0;	if (verbose)		printk("Unloading module mxser ...\n");	if ((err |= tty_unregister_driver(&mxvar_cdriver)))		printk("Couldn't unregister MOXA Smartio family callout driver\n");	if ((err |= tty_unregister_driver(&mxvar_sdriver)))		printk("Couldn't unregister MOXA Smartio family serial driver\n");	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");}#endifint 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;		info->tqueue.routine = mxser_do_softint;		info->tqueue.data = info;		info->callout_termios = mxvar_cdriver.init_termios;		info->normal_termios = mxvar_sdriver.init_termios;		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 - 1]);		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;}static 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 - 1];	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);}int mxser_init(void){	int i, m, retval, b;	int n, index;	int ret1, ret2;	struct mxser_hwconf hwconf;	printk("MOXA Smartio family driver version %s\n", MXSER_VERSION);	/* Initialize the tty_driver structure */

⌨️ 快捷键说明

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