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 + -
显示快捷键?