stallion.c

来自「linux 内核源代码」· C语言 代码 · 共 2,551 行 · 第 1/5 页

C
2,551
字号
/*****************************************************************************//* *	stallion.c  -- stallion multiport serial driver. * *	Copyright (C) 1996-1999  Stallion Technologies *	Copyright (C) 1994-1996  Greg Ungerer. * *	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. *//*****************************************************************************/#include <linux/module.h>#include <linux/slab.h>#include <linux/interrupt.h>#include <linux/tty.h>#include <linux/tty_flip.h>#include <linux/serial.h>#include <linux/cd1400.h>#include <linux/sc26198.h>#include <linux/comstats.h>#include <linux/stallion.h>#include <linux/ioport.h>#include <linux/init.h>#include <linux/smp_lock.h>#include <linux/device.h>#include <linux/delay.h>#include <linux/ctype.h>#include <asm/io.h>#include <asm/uaccess.h>#include <linux/pci.h>/*****************************************************************************//* *	Define different board types. Use the standard Stallion "assigned" *	board numbers. Boards supported in this driver are abbreviated as *	EIO = EasyIO and ECH = EasyConnection 8/32. */#define	BRD_EASYIO	20#define	BRD_ECH		21#define	BRD_ECHMC	22#define	BRD_ECHPCI	26#define	BRD_ECH64PCI	27#define	BRD_EASYIOPCI	28struct stlconf {	unsigned int	brdtype;	int		ioaddr1;	int		ioaddr2;	unsigned long	memaddr;	int		irq;	int		irqtype;};static unsigned int stl_nrbrds;/*****************************************************************************//* *	Define some important driver characteristics. Device major numbers *	allocated as per Linux Device Registry. */#ifndef	STL_SIOMEMMAJOR#define	STL_SIOMEMMAJOR		28#endif#ifndef	STL_SERIALMAJOR#define	STL_SERIALMAJOR		24#endif#ifndef	STL_CALLOUTMAJOR#define	STL_CALLOUTMAJOR	25#endif/* *	Set the TX buffer size. Bigger is better, but we don't want *	to chew too much memory with buffers! */#define	STL_TXBUFLOW		512#define	STL_TXBUFSIZE		4096/*****************************************************************************//* *	Define our local driver identity first. Set up stuff to deal with *	all the local structures required by a serial tty driver. */static char	*stl_drvtitle = "Stallion Multiport Serial Driver";static char	*stl_drvname = "stallion";static char	*stl_drvversion = "5.6.0";static struct tty_driver	*stl_serial;/* *	Define a local default termios struct. All ports will be created *	with this termios initially. Basically all it defines is a raw port *	at 9600, 8 data bits, 1 stop bit. */static struct ktermios		stl_deftermios = {	.c_cflag	= (B9600 | CS8 | CREAD | HUPCL | CLOCAL),	.c_cc		= INIT_C_CC,	.c_ispeed	= 9600,	.c_ospeed	= 9600,};/* *	Define global place to put buffer overflow characters. */static char		stl_unwanted[SC26198_RXFIFOSIZE];/*****************************************************************************/static DEFINE_MUTEX(stl_brdslock);static struct stlbrd		*stl_brds[STL_MAXBRDS];/* *	Per board state flags. Used with the state field of the board struct. *	Not really much here! */#define	BRD_FOUND	0x1#define STL_PROBED	0x2/* *	Define the port structure istate flags. These set of flags are *	modified at interrupt time - so setting and reseting them needs *	to be atomic. Use the bit clear/setting routines for this. */#define	ASYI_TXBUSY	1#define	ASYI_TXLOW	2#define	ASYI_DCDCHANGE	3#define	ASYI_TXFLOWED	4/* *	Define an array of board names as printable strings. Handy for *	referencing boards when printing trace and stuff. */static char	*stl_brdnames[] = {	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	"EasyIO",	"EC8/32-AT",	"EC8/32-MC",	NULL,	NULL,	NULL,	"EC8/32-PCI",	"EC8/64-PCI",	"EasyIO-PCI",};/*****************************************************************************//* *	Define some string labels for arguments passed from the module *	load line. These allow for easy board definitions, and easy *	modification of the io, memory and irq resoucres. */static unsigned int stl_nargs;static char	*board0[4];static char	*board1[4];static char	*board2[4];static char	*board3[4];static char	**stl_brdsp[] = {	(char **) &board0,	(char **) &board1,	(char **) &board2,	(char **) &board3};/* *	Define a set of common board names, and types. This is used to *	parse any module arguments. */static struct {	char	*name;	int	type;} stl_brdstr[] = {	{ "easyio", BRD_EASYIO },	{ "eio", BRD_EASYIO },	{ "20", BRD_EASYIO },	{ "ec8/32", BRD_ECH },	{ "ec8/32-at", BRD_ECH },	{ "ec8/32-isa", BRD_ECH },	{ "ech", BRD_ECH },	{ "echat", BRD_ECH },	{ "21", BRD_ECH },	{ "ec8/32-mc", BRD_ECHMC },	{ "ec8/32-mca", BRD_ECHMC },	{ "echmc", BRD_ECHMC },	{ "echmca", BRD_ECHMC },	{ "22", BRD_ECHMC },	{ "ec8/32-pc", BRD_ECHPCI },	{ "ec8/32-pci", BRD_ECHPCI },	{ "26", BRD_ECHPCI },	{ "ec8/64-pc", BRD_ECH64PCI },	{ "ec8/64-pci", BRD_ECH64PCI },	{ "ech-pci", BRD_ECH64PCI },	{ "echpci", BRD_ECH64PCI },	{ "echpc", BRD_ECH64PCI },	{ "27", BRD_ECH64PCI },	{ "easyio-pc", BRD_EASYIOPCI },	{ "easyio-pci", BRD_EASYIOPCI },	{ "eio-pci", BRD_EASYIOPCI },	{ "eiopci", BRD_EASYIOPCI },	{ "28", BRD_EASYIOPCI },};/* *	Define the module agruments. */module_param_array(board0, charp, &stl_nargs, 0);MODULE_PARM_DESC(board0, "Board 0 config -> name[,ioaddr[,ioaddr2][,irq]]");module_param_array(board1, charp, &stl_nargs, 0);MODULE_PARM_DESC(board1, "Board 1 config -> name[,ioaddr[,ioaddr2][,irq]]");module_param_array(board2, charp, &stl_nargs, 0);MODULE_PARM_DESC(board2, "Board 2 config -> name[,ioaddr[,ioaddr2][,irq]]");module_param_array(board3, charp, &stl_nargs, 0);MODULE_PARM_DESC(board3, "Board 3 config -> name[,ioaddr[,ioaddr2][,irq]]");/*****************************************************************************//* *	Hardware ID bits for the EasyIO and ECH boards. These defines apply *	to the directly accessible io ports of these boards (not the uarts - *	they are in cd1400.h and sc26198.h). */#define	EIO_8PORTRS	0x04#define	EIO_4PORTRS	0x05#define	EIO_8PORTDI	0x00#define	EIO_8PORTM	0x06#define	EIO_MK3		0x03#define	EIO_IDBITMASK	0x07#define	EIO_BRDMASK	0xf0#define	ID_BRD4		0x10#define	ID_BRD8		0x20#define	ID_BRD16	0x30#define	EIO_INTRPEND	0x08#define	EIO_INTEDGE	0x00#define	EIO_INTLEVEL	0x08#define	EIO_0WS		0x10#define	ECH_ID		0xa0#define	ECH_IDBITMASK	0xe0#define	ECH_BRDENABLE	0x08#define	ECH_BRDDISABLE	0x00#define	ECH_INTENABLE	0x01#define	ECH_INTDISABLE	0x00#define	ECH_INTLEVEL	0x02#define	ECH_INTEDGE	0x00#define	ECH_INTRPEND	0x01#define	ECH_BRDRESET	0x01#define	ECHMC_INTENABLE	0x01#define	ECHMC_BRDRESET	0x02#define	ECH_PNLSTATUS	2#define	ECH_PNL16PORT	0x20#define	ECH_PNLIDMASK	0x07#define	ECH_PNLXPID	0x40#define	ECH_PNLINTRPEND	0x80#define	ECH_ADDR2MASK	0x1e0/* *	Define the vector mapping bits for the programmable interrupt board *	hardware. These bits encode the interrupt for the board to use - it *	is software selectable (except the EIO-8M). */static unsigned char	stl_vecmap[] = {	0xff, 0xff, 0xff, 0x04, 0x06, 0x05, 0xff, 0x07,	0xff, 0xff, 0x00, 0x02, 0x01, 0xff, 0xff, 0x03};/* *	Lock ordering is that you may not take stallion_lock holding *	brd_lock. */static spinlock_t brd_lock; 		/* Guard the board mapping */static spinlock_t stallion_lock;	/* Guard the tty driver *//* *	Set up enable and disable macros for the ECH boards. They require *	the secondary io address space to be activated and deactivated. *	This way all ECH boards can share their secondary io region. *	If this is an ECH-PCI board then also need to set the page pointer *	to point to the correct page. */#define	BRDENABLE(brdnr,pagenr)						\	if (stl_brds[(brdnr)]->brdtype == BRD_ECH)			\		outb((stl_brds[(brdnr)]->ioctrlval | ECH_BRDENABLE),	\			stl_brds[(brdnr)]->ioctrl);			\	else if (stl_brds[(brdnr)]->brdtype == BRD_ECHPCI)		\		outb((pagenr), stl_brds[(brdnr)]->ioctrl);#define	BRDDISABLE(brdnr)						\	if (stl_brds[(brdnr)]->brdtype == BRD_ECH)			\		outb((stl_brds[(brdnr)]->ioctrlval | ECH_BRDDISABLE),	\			stl_brds[(brdnr)]->ioctrl);#define	STL_CD1400MAXBAUD	230400#define	STL_SC26198MAXBAUD	460800#define	STL_BAUDBASE		115200#define	STL_CLOSEDELAY		(5 * HZ / 10)/*****************************************************************************//* *	Define the Stallion PCI vendor and device IDs. */#ifndef	PCI_VENDOR_ID_STALLION#define	PCI_VENDOR_ID_STALLION		0x124d#endif#ifndef PCI_DEVICE_ID_ECHPCI832#define	PCI_DEVICE_ID_ECHPCI832		0x0000#endif#ifndef PCI_DEVICE_ID_ECHPCI864#define	PCI_DEVICE_ID_ECHPCI864		0x0002#endif#ifndef PCI_DEVICE_ID_EIOPCI#define	PCI_DEVICE_ID_EIOPCI		0x0003#endif/* *	Define structure to hold all Stallion PCI boards. */static struct pci_device_id stl_pcibrds[] = {	{ PCI_DEVICE(PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_ECHPCI864),		.driver_data = BRD_ECH64PCI },	{ PCI_DEVICE(PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_EIOPCI),		.driver_data = BRD_EASYIOPCI },	{ PCI_DEVICE(PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_ECHPCI832),		.driver_data = BRD_ECHPCI },	{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410),		.driver_data = BRD_ECHPCI },	{ }};MODULE_DEVICE_TABLE(pci, stl_pcibrds);/*****************************************************************************//* *	Define macros to extract a brd/port number from a minor number. */#define	MINOR2BRD(min)		(((min) & 0xc0) >> 6)#define	MINOR2PORT(min)		((min) & 0x3f)/* *	Define a baud rate table that converts termios baud rate selector *	into the actual baud rate value. All baud rate calculations are *	based on the actual baud rate required. */static unsigned int	stl_baudrates[] = {	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,	9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600};/*****************************************************************************//* *	Declare all those functions in this driver! */static int	stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg);static int	stl_brdinit(struct stlbrd *brdp);static int	stl_getportstats(struct stlport *portp, comstats_t __user *cp);static int	stl_clrportstats(struct stlport *portp, comstats_t __user *cp);static int	stl_waitcarrier(struct stlport *portp, struct file *filp);/* *	CD1400 uart specific handling functions. */static void	stl_cd1400setreg(struct stlport *portp, int regnr, int value);static int	stl_cd1400getreg(struct stlport *portp, int regnr);static int	stl_cd1400updatereg(struct stlport *portp, int regnr, int value);static int	stl_cd1400panelinit(struct stlbrd *brdp, struct stlpanel *panelp);static void	stl_cd1400portinit(struct stlbrd *brdp, struct stlpanel *panelp, struct stlport *portp);static void	stl_cd1400setport(struct stlport *portp, struct ktermios *tiosp);static int	stl_cd1400getsignals(struct stlport *portp);static void	stl_cd1400setsignals(struct stlport *portp, int dtr, int rts);static void	stl_cd1400ccrwait(struct stlport *portp);static void	stl_cd1400enablerxtx(struct stlport *portp, int rx, int tx);static void	stl_cd1400startrxtx(struct stlport *portp, int rx, int tx);static void	stl_cd1400disableintrs(struct stlport *portp);static void	stl_cd1400sendbreak(struct stlport *portp, int len);static void	stl_cd1400flowctrl(struct stlport *portp, int state);static void	stl_cd1400sendflow(struct stlport *portp, int state);static void	stl_cd1400flush(struct stlport *portp);static int	stl_cd1400datastate(struct stlport *portp);static void	stl_cd1400eiointr(struct stlpanel *panelp, unsigned int iobase);static void	stl_cd1400echintr(struct stlpanel *panelp, unsigned int iobase);static void	stl_cd1400txisr(struct stlpanel *panelp, int ioaddr);static void	stl_cd1400rxisr(struct stlpanel *panelp, int ioaddr);static void	stl_cd1400mdmisr(struct stlpanel *panelp, int ioaddr);static inline int	stl_cd1400breakisr(struct stlport *portp, int ioaddr);/* *	SC26198 uart specific handling functions. */static void	stl_sc26198setreg(struct stlport *portp, int regnr, int value);static int	stl_sc26198getreg(struct stlport *portp, int regnr);static int	stl_sc26198updatereg(struct stlport *portp, int regnr, int value);static int	stl_sc26198getglobreg(struct stlport *portp, int regnr);static int	stl_sc26198panelinit(struct stlbrd *brdp, struct stlpanel *panelp);static void	stl_sc26198portinit(struct stlbrd *brdp, struct stlpanel *panelp, struct stlport *portp);static void	stl_sc26198setport(struct stlport *portp, struct ktermios *tiosp);static int	stl_sc26198getsignals(struct stlport *portp);static void	stl_sc26198setsignals(struct stlport *portp, int dtr, int rts);static void	stl_sc26198enablerxtx(struct stlport *portp, int rx, int tx);static void	stl_sc26198startrxtx(struct stlport *portp, int rx, int tx);static void	stl_sc26198disableintrs(struct stlport *portp);static void	stl_sc26198sendbreak(struct stlport *portp, int len);static void	stl_sc26198flowctrl(struct stlport *portp, int state);static void	stl_sc26198sendflow(struct stlport *portp, int state);static void	stl_sc26198flush(struct stlport *portp);static int	stl_sc26198datastate(struct stlport *portp);static void	stl_sc26198wait(struct stlport *portp);static void	stl_sc26198txunflow(struct stlport *portp, struct tty_struct *tty);static void	stl_sc26198intr(struct stlpanel *panelp, unsigned int iobase);static void	stl_sc26198txisr(struct stlport *port);static void	stl_sc26198rxisr(struct stlport *port, unsigned int iack);static void	stl_sc26198rxbadch(struct stlport *portp, unsigned char status, char ch);static void	stl_sc26198rxbadchars(struct stlport *portp);static void	stl_sc26198otherisr(struct stlport *port, unsigned int iack);/*****************************************************************************//* *	Generic UART support structure. */typedef struct uart {	int	(*panelinit)(struct stlbrd *brdp, struct stlpanel *panelp);	void	(*portinit)(struct stlbrd *brdp, struct stlpanel *panelp, struct stlport *portp);	void	(*setport)(struct stlport *portp, struct ktermios *tiosp);	int	(*getsignals)(struct stlport *portp);	void	(*setsignals)(struct stlport *portp, int dtr, int rts);	void	(*enablerxtx)(struct stlport *portp, int rx, int tx);	void	(*startrxtx)(struct stlport *portp, int rx, int tx);	void	(*disableintrs)(struct stlport *portp);	void	(*sendbreak)(struct stlport *portp, int len);	void	(*flowctrl)(struct stlport *portp, int state);	void	(*sendflow)(struct stlport *portp, int state);	void	(*flush)(struct stlport *portp);	int	(*datastate)(struct stlport *portp);	void	(*intr)(struct stlpanel *panelp, unsigned int iobase);} uart_t;/* *	Define some macros to make calling these functions nice and clean. */#define	stl_panelinit		(* ((uart_t *) panelp->uartp)->panelinit)#define	stl_portinit		(* ((uart_t *) portp->uartp)->portinit)#define	stl_setport		(* ((uart_t *) portp->uartp)->setport)#define	stl_getsignals		(* ((uart_t *) portp->uartp)->getsignals)#define	stl_setsignals		(* ((uart_t *) portp->uartp)->setsignals)#define	stl_enablerxtx		(* ((uart_t *) portp->uartp)->enablerxtx)#define	stl_startrxtx		(* ((uart_t *) portp->uartp)->startrxtx)#define	stl_disableintrs	(* ((uart_t *) portp->uartp)->disableintrs)#define	stl_sendbreak		(* ((uart_t *) portp->uartp)->sendbreak)#define	stl_flowctrl		(* ((uart_t *) portp->uartp)->flowctrl)#define	stl_sendflow		(* ((uart_t *) portp->uartp)->sendflow)#define	stl_flush		(* ((uart_t *) portp->uartp)->flush)#define	stl_datastate		(* ((uart_t *) portp->uartp)->datastate)/*****************************************************************************//*

⌨️ 快捷键说明

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