X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fchar%2Fstallion.c;h=e45113a7a472f7f1035d3fd92b2909b237bd298b;hb=refs%2Fheads%2Fvserver;hp=90018ce17c57fd3bffea7a94786bc3465188cc6d;hpb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;p=linux-2.6.git diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c index 90018ce17..e45113a7a 100644 --- a/drivers/char/stallion.c +++ b/drivers/char/stallion.c @@ -26,7 +26,6 @@ /*****************************************************************************/ -#include #include #include #include @@ -40,15 +39,14 @@ #include #include #include -#include #include +#include +#include #include #include -#ifdef CONFIG_PCI #include -#endif /*****************************************************************************/ @@ -64,45 +62,16 @@ #define BRD_ECH64PCI 27 #define BRD_EASYIOPCI 28 -/* - * Define a configuration structure to hold the board configuration. - * Need to set this up in the code (for now) with the boards that are - * to be configured into the system. This is what needs to be modified - * when adding/removing/modifying boards. Each line entry in the - * stl_brdconf[] array is a board. Each line contains io/irq/memory - * ranges for that board (as well as what type of board it is). - * Some examples: - * { BRD_EASYIO, 0x2a0, 0, 0, 10, 0 }, - * This line would configure an EasyIO board (4 or 8, no difference), - * at io address 2a0 and irq 10. - * Another example: - * { BRD_ECH, 0x2a8, 0x280, 0, 12, 0 }, - * This line will configure an EasyConnection 8/32 board at primary io - * address 2a8, secondary io address 280 and irq 12. - * Enter as many lines into this array as you want (only the first 4 - * will actually be used!). Any combination of EasyIO and EasyConnection - * boards can be specified. EasyConnection 8/32 boards can share their - * secondary io addresses between each other. - * - * NOTE: there is no need to put any entries in this table for PCI - * boards. They will be found automatically by the driver - provided - * PCI BIOS32 support is compiled into the kernel. - */ - -typedef struct { - int brdtype; +struct stlconf { + unsigned int brdtype; int ioaddr1; int ioaddr2; unsigned long memaddr; int irq; int irqtype; -} stlconf_t; - -static stlconf_t stl_brdconf[] = { - /*{ BRD_EASYIO, 0x2a0, 0, 0, 10, 0 },*/ }; -static int stl_nrbrds = sizeof(stl_brdconf) / sizeof(stlconf_t); +static unsigned int stl_nrbrds; /*****************************************************************************/ @@ -139,57 +108,35 @@ static char *stl_drvversion = "5.6.0"; static struct tty_driver *stl_serial; -/* - * We will need to allocate a temporary write buffer for chars that - * come direct from user space. The problem is that a copy from user - * space might cause a page fault (typically on a system that is - * swapping!). All ports will share one buffer - since if the system - * is already swapping a shared buffer won't make things any worse. - */ -static char *stl_tmpwritebuf; -static DECLARE_MUTEX(stl_tmpwritesem); - /* * 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 termios stl_deftermios = { +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 stats structures. Not used often, and can be - * re-used for each stats call. - */ -static comstats_t stl_comstats; -static combrd_t stl_brdstats; -static stlbrd_t stl_dummybrd; -static stlport_t stl_dummyport; - /* * Define global place to put buffer overflow characters. */ static char stl_unwanted[SC26198_RXFIFOSIZE]; -/* - * Keep track of what interrupts we have requested for us. - * We don't need to request an interrupt twice if it is being - * shared with another Stallion board. - */ -static int stl_gotintrs[STL_MAXBRDS]; -static int stl_numintrs; - /*****************************************************************************/ -static stlbrd_t *stl_brds[STL_MAXBRDS]; +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 @@ -206,32 +153,32 @@ static stlbrd_t *stl_brds[STL_MAXBRDS]; * referencing boards when printing trace and stuff. */ static char *stl_brdnames[] = { - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, + 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", - (char *) NULL, - (char *) NULL, - (char *) NULL, + NULL, + NULL, + NULL, "EC8/32-PCI", "EC8/64-PCI", "EasyIO-PCI", @@ -239,13 +186,12 @@ static char *stl_brdnames[] = { /*****************************************************************************/ -#ifdef MODULE /* * 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]; @@ -263,12 +209,10 @@ static char **stl_brdsp[] = { * parse any module arguments. */ -typedef struct stlbrdtype { +static struct { char *name; int type; -} stlbrdtype_t; - -static stlbrdtype_t stl_brdstr[] = { +} stl_brdstr[] = { { "easyio", BRD_EASYIO }, { "eio", BRD_EASYIO }, { "20", BRD_EASYIO }, @@ -302,21 +246,16 @@ static stlbrdtype_t stl_brdstr[] = { /* * Define the module agruments. */ -MODULE_AUTHOR("Greg Ungerer"); -MODULE_DESCRIPTION("Stallion Multiport Serial Driver"); -MODULE_LICENSE("GPL"); -MODULE_PARM(board0, "1-4s"); +module_param_array(board0, charp, &stl_nargs, 0); MODULE_PARM_DESC(board0, "Board 0 config -> name[,ioaddr[,ioaddr2][,irq]]"); -MODULE_PARM(board1, "1-4s"); +module_param_array(board1, charp, &stl_nargs, 0); MODULE_PARM_DESC(board1, "Board 1 config -> name[,ioaddr[,ioaddr2][,irq]]"); -MODULE_PARM(board2, "1-4s"); +module_param_array(board2, charp, &stl_nargs, 0); MODULE_PARM_DESC(board2, "Board 2 config -> name[,ioaddr[,ioaddr2][,irq]]"); -MODULE_PARM(board3, "1-4s"); +module_param_array(board3, charp, &stl_nargs, 0); MODULE_PARM_DESC(board3, "Board 3 config -> name[,ioaddr[,ioaddr2][,irq]]"); -#endif - /*****************************************************************************/ /* @@ -373,6 +312,14 @@ static unsigned char stl_vecmap[] = { 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. @@ -400,8 +347,6 @@ static unsigned char stl_vecmap[] = { /*****************************************************************************/ -#ifdef CONFIG_PCI - /* * Define the Stallion PCI vendor and device IDs. */ @@ -421,22 +366,19 @@ static unsigned char stl_vecmap[] = { /* * Define structure to hold all Stallion PCI boards. */ -typedef struct stlpcibrd { - unsigned short vendid; - unsigned short devid; - int brdtype; -} stlpcibrd_t; - -static stlpcibrd_t stl_pcibrds[] = { - { PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_ECHPCI864, BRD_ECH64PCI }, - { PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_EIOPCI, BRD_EASYIOPCI }, - { PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_ECHPCI832, BRD_ECHPCI }, - { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410, BRD_ECHPCI }, -}; - -static int stl_nrpcibrds = sizeof(stl_pcibrds) / sizeof(stlpcibrd_t); -#endif +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); /*****************************************************************************/ @@ -456,139 +398,74 @@ static unsigned int stl_baudrates[] = { 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600 }; -/* - * Define some handy local macros... - */ -#undef MIN -#define MIN(a,b) (((a) <= (b)) ? (a) : (b)) - -#undef TOLOWER -#define TOLOWER(x) ((((x) >= 'A') && ((x) <= 'Z')) ? ((x) + 0x20) : (x)) - /*****************************************************************************/ /* * Declare all those functions in this driver! */ -#ifdef MODULE -static void stl_argbrds(void); -static int stl_parsebrd(stlconf_t *confp, char **argp); - -static unsigned long stl_atol(char *str); -#endif - -int stl_init(void); -static int stl_open(struct tty_struct *tty, struct file *filp); -static void stl_close(struct tty_struct *tty, struct file *filp); -static int stl_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count); -static void stl_putchar(struct tty_struct *tty, unsigned char ch); -static void stl_flushchars(struct tty_struct *tty); -static int stl_writeroom(struct tty_struct *tty); -static int stl_charsinbuffer(struct tty_struct *tty); -static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg); -static void stl_settermios(struct tty_struct *tty, struct termios *old); -static void stl_throttle(struct tty_struct *tty); -static void stl_unthrottle(struct tty_struct *tty); -static void stl_stop(struct tty_struct *tty); -static void stl_start(struct tty_struct *tty); -static void stl_flushbuffer(struct tty_struct *tty); -static void stl_breakctl(struct tty_struct *tty, int state); -static void stl_waituntilsent(struct tty_struct *tty, int timeout); -static void stl_sendxchar(struct tty_struct *tty, char ch); -static void stl_hangup(struct tty_struct *tty); static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg); -static int stl_portinfo(stlport_t *portp, int portnr, char *pos); -static int stl_readproc(char *page, char **start, off_t off, int count, int *eof, void *data); - -static int stl_brdinit(stlbrd_t *brdp); -static int stl_initports(stlbrd_t *brdp, stlpanel_t *panelp); -static int stl_mapirq(int irq, char *name); -static int stl_getserial(stlport_t *portp, struct serial_struct __user *sp); -static int stl_setserial(stlport_t *portp, struct serial_struct __user *sp); -static int stl_getbrdstats(combrd_t __user *bp); -static int stl_getportstats(stlport_t *portp, comstats_t __user *cp); -static int stl_clrportstats(stlport_t *portp, comstats_t __user *cp); -static int stl_getportstruct(stlport_t __user *arg); -static int stl_getbrdstruct(stlbrd_t __user *arg); -static int stl_waitcarrier(stlport_t *portp, struct file *filp); -static void stl_delay(int len); -static void stl_eiointr(stlbrd_t *brdp); -static void stl_echatintr(stlbrd_t *brdp); -static void stl_echmcaintr(stlbrd_t *brdp); -static void stl_echpciintr(stlbrd_t *brdp); -static void stl_echpci64intr(stlbrd_t *brdp); -static void stl_offintr(void *private); -static void *stl_memalloc(int len); -static stlbrd_t *stl_allocbrd(void); -static stlport_t *stl_getport(int brdnr, int panelnr, int portnr); - -static inline int stl_initbrds(void); -static inline int stl_initeio(stlbrd_t *brdp); -static inline int stl_initech(stlbrd_t *brdp); -static inline int stl_getbrdnr(void); - -#ifdef CONFIG_PCI -static inline int stl_findpcibrds(void); -static inline int stl_initpcibrd(int brdtype, struct pci_dev *devp); -#endif +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(stlport_t *portp, int regnr, int value); -static int stl_cd1400getreg(stlport_t *portp, int regnr); -static int stl_cd1400updatereg(stlport_t *portp, int regnr, int value); -static int stl_cd1400panelinit(stlbrd_t *brdp, stlpanel_t *panelp); -static void stl_cd1400portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp); -static void stl_cd1400setport(stlport_t *portp, struct termios *tiosp); -static int stl_cd1400getsignals(stlport_t *portp); -static void stl_cd1400setsignals(stlport_t *portp, int dtr, int rts); -static void stl_cd1400ccrwait(stlport_t *portp); -static void stl_cd1400enablerxtx(stlport_t *portp, int rx, int tx); -static void stl_cd1400startrxtx(stlport_t *portp, int rx, int tx); -static void stl_cd1400disableintrs(stlport_t *portp); -static void stl_cd1400sendbreak(stlport_t *portp, int len); -static void stl_cd1400flowctrl(stlport_t *portp, int state); -static void stl_cd1400sendflow(stlport_t *portp, int state); -static void stl_cd1400flush(stlport_t *portp); -static int stl_cd1400datastate(stlport_t *portp); -static void stl_cd1400eiointr(stlpanel_t *panelp, unsigned int iobase); -static void stl_cd1400echintr(stlpanel_t *panelp, unsigned int iobase); -static void stl_cd1400txisr(stlpanel_t *panelp, int ioaddr); -static void stl_cd1400rxisr(stlpanel_t *panelp, int ioaddr); -static void stl_cd1400mdmisr(stlpanel_t *panelp, int ioaddr); - -static inline int stl_cd1400breakisr(stlport_t *portp, int ioaddr); +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(stlport_t *portp, int regnr, int value); -static int stl_sc26198getreg(stlport_t *portp, int regnr); -static int stl_sc26198updatereg(stlport_t *portp, int regnr, int value); -static int stl_sc26198getglobreg(stlport_t *portp, int regnr); -static int stl_sc26198panelinit(stlbrd_t *brdp, stlpanel_t *panelp); -static void stl_sc26198portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp); -static void stl_sc26198setport(stlport_t *portp, struct termios *tiosp); -static int stl_sc26198getsignals(stlport_t *portp); -static void stl_sc26198setsignals(stlport_t *portp, int dtr, int rts); -static void stl_sc26198enablerxtx(stlport_t *portp, int rx, int tx); -static void stl_sc26198startrxtx(stlport_t *portp, int rx, int tx); -static void stl_sc26198disableintrs(stlport_t *portp); -static void stl_sc26198sendbreak(stlport_t *portp, int len); -static void stl_sc26198flowctrl(stlport_t *portp, int state); -static void stl_sc26198sendflow(stlport_t *portp, int state); -static void stl_sc26198flush(stlport_t *portp); -static int stl_sc26198datastate(stlport_t *portp); -static void stl_sc26198wait(stlport_t *portp); -static void stl_sc26198txunflow(stlport_t *portp, struct tty_struct *tty); -static void stl_sc26198intr(stlpanel_t *panelp, unsigned int iobase); -static void stl_sc26198txisr(stlport_t *port); -static void stl_sc26198rxisr(stlport_t *port, unsigned int iack); -static void stl_sc26198rxbadch(stlport_t *portp, unsigned char status, char ch); -static void stl_sc26198rxbadchars(stlport_t *portp); -static void stl_sc26198otherisr(stlport_t *port, unsigned int iack); +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); /*****************************************************************************/ @@ -596,20 +473,20 @@ static void stl_sc26198otherisr(stlport_t *port, unsigned int iack); * Generic UART support structure. */ typedef struct uart { - int (*panelinit)(stlbrd_t *brdp, stlpanel_t *panelp); - void (*portinit)(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp); - void (*setport)(stlport_t *portp, struct termios *tiosp); - int (*getsignals)(stlport_t *portp); - void (*setsignals)(stlport_t *portp, int dtr, int rts); - void (*enablerxtx)(stlport_t *portp, int rx, int tx); - void (*startrxtx)(stlport_t *portp, int rx, int tx); - void (*disableintrs)(stlport_t *portp); - void (*sendbreak)(stlport_t *portp, int len); - void (*flowctrl)(stlport_t *portp, int state); - void (*sendflow)(stlport_t *portp, int state); - void (*flush)(stlport_t *portp); - int (*datastate)(stlport_t *portp); - void (*intr)(stlpanel_t *panelp, unsigned int iobase); + 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; /* @@ -718,7 +595,7 @@ static unsigned int sc26198_baudtable[] = { 230400, 460800, 921600 }; -#define SC26198_NRBAUDS (sizeof(sc26198_baudtable) / sizeof(unsigned int)) +#define SC26198_NRBAUDS ARRAY_SIZE(sc26198_baudtable) /*****************************************************************************/ @@ -726,250 +603,59 @@ static unsigned int sc26198_baudtable[] = { * Define the driver info for a user level control device. Used mainly * to get at port stats - only not using the port device itself. */ -static struct file_operations stl_fsiomem = { +static const struct file_operations stl_fsiomem = { .owner = THIS_MODULE, .ioctl = stl_memioctl, }; -/*****************************************************************************/ - -static struct class_simple *stallion_class; - -#ifdef MODULE - -/* - * Loadable module initialization stuff. - */ - -static int __init stallion_module_init(void) -{ - unsigned long flags; - -#ifdef DEBUG - printk("init_module()\n"); -#endif - - save_flags(flags); - cli(); - stl_init(); - restore_flags(flags); - - return(0); -} - -/*****************************************************************************/ - -static void __exit stallion_module_exit(void) -{ - stlbrd_t *brdp; - stlpanel_t *panelp; - stlport_t *portp; - unsigned long flags; - int i, j, k; - -#ifdef DEBUG - printk("cleanup_module()\n"); -#endif - - printk(KERN_INFO "Unloading %s: version %s\n", stl_drvtitle, - stl_drvversion); - - save_flags(flags); - cli(); - -/* - * Free up all allocated resources used by the ports. This includes - * memory and interrupts. As part of this process we will also do - * a hangup on every open port - to try to flush out any processes - * hanging onto ports. - */ - i = tty_unregister_driver(stl_serial); - put_tty_driver(stl_serial); - if (i) { - printk("STALLION: failed to un-register tty driver, " - "errno=%d\n", -i); - restore_flags(flags); - return; - } - for (i = 0; i < 4; i++) { - devfs_remove("staliomem/%d", i); - class_simple_device_remove(MKDEV(STL_SIOMEMMAJOR, i)); - } - devfs_remove("staliomem"); - if ((i = unregister_chrdev(STL_SIOMEMMAJOR, "staliomem"))) - printk("STALLION: failed to un-register serial memory device, " - "errno=%d\n", -i); - class_simple_destroy(stallion_class); - - if (stl_tmpwritebuf != (char *) NULL) - kfree(stl_tmpwritebuf); - - for (i = 0; (i < stl_nrbrds); i++) { - if ((brdp = stl_brds[i]) == (stlbrd_t *) NULL) - continue; - for (j = 0; (j < STL_MAXPANELS); j++) { - panelp = brdp->panels[j]; - if (panelp == (stlpanel_t *) NULL) - continue; - for (k = 0; (k < STL_PORTSPERPANEL); k++) { - portp = panelp->ports[k]; - if (portp == (stlport_t *) NULL) - continue; - if (portp->tty != (struct tty_struct *) NULL) - stl_hangup(portp->tty); - if (portp->tx.buf != (char *) NULL) - kfree(portp->tx.buf); - kfree(portp); - } - kfree(panelp); - } - - release_region(brdp->ioaddr1, brdp->iosize1); - if (brdp->iosize2 > 0) - release_region(brdp->ioaddr2, brdp->iosize2); - - kfree(brdp); - stl_brds[i] = (stlbrd_t *) NULL; - } - - for (i = 0; (i < stl_numintrs); i++) - free_irq(stl_gotintrs[i], NULL); - - restore_flags(flags); -} - -module_init(stallion_module_init); -module_exit(stallion_module_exit); - -/*****************************************************************************/ +static struct class *stallion_class; /* * Check for any arguments passed in on the module load command line. */ -static void stl_argbrds(void) -{ - stlconf_t conf; - stlbrd_t *brdp; - int nrargs, i; - -#ifdef DEBUG - printk("stl_argbrds()\n"); -#endif - - nrargs = sizeof(stl_brdsp) / sizeof(char **); - - for (i = stl_nrbrds; (i < nrargs); i++) { - memset(&conf, 0, sizeof(conf)); - if (stl_parsebrd(&conf, stl_brdsp[i]) == 0) - continue; - if ((brdp = stl_allocbrd()) == (stlbrd_t *) NULL) - continue; - stl_nrbrds = i + 1; - brdp->brdnr = i; - brdp->brdtype = conf.brdtype; - brdp->ioaddr1 = conf.ioaddr1; - brdp->ioaddr2 = conf.ioaddr2; - brdp->irq = conf.irq; - brdp->irqtype = conf.irqtype; - stl_brdinit(brdp); - } -} - -/*****************************************************************************/ - -/* - * Convert an ascii string number into an unsigned long. - */ - -static unsigned long stl_atol(char *str) -{ - unsigned long val; - int base, c; - char *sp; - - val = 0; - sp = str; - if ((*sp == '0') && (*(sp+1) == 'x')) { - base = 16; - sp += 2; - } else if (*sp == '0') { - base = 8; - sp++; - } else { - base = 10; - } - - for (; (*sp != 0); sp++) { - c = (*sp > '9') ? (TOLOWER(*sp) - 'a' + 10) : (*sp - '0'); - if ((c < 0) || (c >= base)) { - printk("STALLION: invalid argument %s\n", str); - val = 0; - break; - } - val = (val * base) + c; - } - return(val); -} - /*****************************************************************************/ /* * Parse the supplied argument string, into the board conf struct. */ -static int stl_parsebrd(stlconf_t *confp, char **argp) +static int __init stl_parsebrd(struct stlconf *confp, char **argp) { char *sp; - int nrbrdnames, i; + unsigned int i; -#ifdef DEBUG - printk("stl_parsebrd(confp=%x,argp=%x)\n", (int) confp, (int) argp); -#endif + pr_debug("stl_parsebrd(confp=%p,argp=%p)\n", confp, argp); - if ((argp[0] == (char *) NULL) || (*argp[0] == 0)) - return(0); + if ((argp[0] == NULL) || (*argp[0] == 0)) + return 0; - for (sp = argp[0], i = 0; ((*sp != 0) && (i < 25)); sp++, i++) - *sp = TOLOWER(*sp); + for (sp = argp[0], i = 0; (*sp != 0) && (i < 25); sp++, i++) + *sp = tolower(*sp); - nrbrdnames = sizeof(stl_brdstr) / sizeof(stlbrdtype_t); - for (i = 0; (i < nrbrdnames); i++) { + for (i = 0; i < ARRAY_SIZE(stl_brdstr); i++) if (strcmp(stl_brdstr[i].name, argp[0]) == 0) break; - } - if (i >= nrbrdnames) { + + if (i == ARRAY_SIZE(stl_brdstr)) { printk("STALLION: unknown board name, %s?\n", argp[0]); - return(0); + return 0; } confp->brdtype = stl_brdstr[i].type; i = 1; - if ((argp[i] != (char *) NULL) && (*argp[i] != 0)) - confp->ioaddr1 = stl_atol(argp[i]); + if ((argp[i] != NULL) && (*argp[i] != 0)) + confp->ioaddr1 = simple_strtoul(argp[i], NULL, 0); i++; if (confp->brdtype == BRD_ECH) { - if ((argp[i] != (char *) NULL) && (*argp[i] != 0)) - confp->ioaddr2 = stl_atol(argp[i]); + if ((argp[i] != NULL) && (*argp[i] != 0)) + confp->ioaddr2 = simple_strtoul(argp[i], NULL, 0); i++; } - if ((argp[i] != (char *) NULL) && (*argp[i] != 0)) - confp->irq = stl_atol(argp[i]); - return(1); -} - -#endif - -/*****************************************************************************/ - -/* - * Local driver kernel memory allocation routine. - */ - -static void *stl_memalloc(int len) -{ - return((void *) kmalloc(len, GFP_KERNEL)); + if ((argp[i] != NULL) && (*argp[i] != 0)) + confp->irq = simple_strtoul(argp[i], NULL, 0); + return 1; } /*****************************************************************************/ @@ -978,46 +664,42 @@ static void *stl_memalloc(int len) * Allocate a new board structure. Fill out the basic info in it. */ -static stlbrd_t *stl_allocbrd(void) +static struct stlbrd *stl_allocbrd(void) { - stlbrd_t *brdp; + struct stlbrd *brdp; - brdp = (stlbrd_t *) stl_memalloc(sizeof(stlbrd_t)); - if (brdp == (stlbrd_t *) NULL) { - printk("STALLION: failed to allocate memory (size=%d)\n", - sizeof(stlbrd_t)); - return((stlbrd_t *) NULL); + brdp = kzalloc(sizeof(struct stlbrd), GFP_KERNEL); + if (!brdp) { + printk("STALLION: failed to allocate memory (size=%Zd)\n", + sizeof(struct stlbrd)); + return NULL; } - memset(brdp, 0, sizeof(stlbrd_t)); brdp->magic = STL_BOARDMAGIC; - return(brdp); + return brdp; } /*****************************************************************************/ static int stl_open(struct tty_struct *tty, struct file *filp) { - stlport_t *portp; - stlbrd_t *brdp; - unsigned int minordev; - int brdnr, panelnr, portnr, rc; - -#ifdef DEBUG - printk("stl_open(tty=%x,filp=%x): device=%s\n", (int) tty, - (int) filp, tty->name); -#endif + struct stlport *portp; + struct stlbrd *brdp; + unsigned int minordev, brdnr, panelnr; + int portnr, rc; + + pr_debug("stl_open(tty=%p,filp=%p): device=%s\n", tty, filp, tty->name); minordev = tty->index; brdnr = MINOR2BRD(minordev); if (brdnr >= stl_nrbrds) - return(-ENODEV); + return -ENODEV; brdp = stl_brds[brdnr]; - if (brdp == (stlbrd_t *) NULL) - return(-ENODEV); + if (brdp == NULL) + return -ENODEV; minordev = MINOR2PORT(minordev); - for (portnr = -1, panelnr = 0; (panelnr < STL_MAXPANELS); panelnr++) { - if (brdp->panels[panelnr] == (stlpanel_t *) NULL) + for (portnr = -1, panelnr = 0; panelnr < STL_MAXPANELS; panelnr++) { + if (brdp->panels[panelnr] == NULL) break; if (minordev < brdp->panels[panelnr]->nrports) { portnr = minordev; @@ -1026,11 +708,11 @@ static int stl_open(struct tty_struct *tty, struct file *filp) minordev -= brdp->panels[panelnr]->nrports; } if (portnr < 0) - return(-ENODEV); + return -ENODEV; portp = brdp->panels[panelnr]->ports[portnr]; - if (portp == (stlport_t *) NULL) - return(-ENODEV); + if (portp == NULL) + return -ENODEV; /* * On the first open of the device setup the port hardware, and @@ -1041,10 +723,10 @@ static int stl_open(struct tty_struct *tty, struct file *filp) portp->refcount++; if ((portp->flags & ASYNC_INITIALIZED) == 0) { - if (portp->tx.buf == (char *) NULL) { - portp->tx.buf = (char *) stl_memalloc(STL_TXBUFSIZE); - if (portp->tx.buf == (char *) NULL) - return(-ENOMEM); + if (!portp->tx.buf) { + portp->tx.buf = kmalloc(STL_TXBUFSIZE, GFP_KERNEL); + if (!portp->tx.buf) + return -ENOMEM; portp->tx.head = portp->tx.buf; portp->tx.tail = portp->tx.buf; } @@ -1066,8 +748,8 @@ static int stl_open(struct tty_struct *tty, struct file *filp) if (portp->flags & ASYNC_CLOSING) { interruptible_sleep_on(&portp->close_wait); if (portp->flags & ASYNC_HUP_NOTIFY) - return(-EAGAIN); - return(-ERESTARTSYS); + return -EAGAIN; + return -ERESTARTSYS; } /* @@ -1075,13 +757,13 @@ static int stl_open(struct tty_struct *tty, struct file *filp) * previous opens still in effect. If we are a normal serial device * then also we might have to wait for carrier. */ - if (!(filp->f_flags & O_NONBLOCK)) { + if (!(filp->f_flags & O_NONBLOCK)) if ((rc = stl_waitcarrier(portp, filp)) != 0) - return(rc); - } + return rc; + portp->flags |= ASYNC_NORMAL_ACTIVE; - return(0); + return 0; } /*****************************************************************************/ @@ -1091,28 +773,27 @@ static int stl_open(struct tty_struct *tty, struct file *filp) * maybe because if we are clocal then we don't need to wait... */ -static int stl_waitcarrier(stlport_t *portp, struct file *filp) +static int stl_waitcarrier(struct stlport *portp, struct file *filp) { unsigned long flags; int rc, doclocal; -#ifdef DEBUG - printk("stl_waitcarrier(portp=%x,filp=%x)\n", (int) portp, (int) filp); -#endif + pr_debug("stl_waitcarrier(portp=%p,filp=%p)\n", portp, filp); rc = 0; doclocal = 0; + spin_lock_irqsave(&stallion_lock, flags); + if (portp->tty->termios->c_cflag & CLOCAL) doclocal++; - save_flags(flags); - cli(); portp->openwaitcnt++; if (! tty_hung_up_p(filp)) portp->refcount--; for (;;) { + /* Takes brd_lock internally */ stl_setsignals(portp, 1, 1); if (tty_hung_up_p(filp) || ((portp->flags & ASYNC_INITIALIZED) == 0)) { @@ -1123,49 +804,92 @@ static int stl_waitcarrier(stlport_t *portp, struct file *filp) break; } if (((portp->flags & ASYNC_CLOSING) == 0) && - (doclocal || (portp->sigs & TIOCM_CD))) { + (doclocal || (portp->sigs & TIOCM_CD))) break; - } if (signal_pending(current)) { rc = -ERESTARTSYS; break; } + /* FIXME */ interruptible_sleep_on(&portp->open_wait); } if (! tty_hung_up_p(filp)) portp->refcount++; portp->openwaitcnt--; - restore_flags(flags); + spin_unlock_irqrestore(&stallion_lock, flags); + + return rc; +} + +/*****************************************************************************/ - return(rc); +static void stl_flushbuffer(struct tty_struct *tty) +{ + struct stlport *portp; + + pr_debug("stl_flushbuffer(tty=%p)\n", tty); + + if (tty == NULL) + return; + portp = tty->driver_data; + if (portp == NULL) + return; + + stl_flush(portp); + tty_wakeup(tty); +} + +/*****************************************************************************/ + +static void stl_waituntilsent(struct tty_struct *tty, int timeout) +{ + struct stlport *portp; + unsigned long tend; + + pr_debug("stl_waituntilsent(tty=%p,timeout=%d)\n", tty, timeout); + + if (tty == NULL) + return; + portp = tty->driver_data; + if (portp == NULL) + return; + + if (timeout == 0) + timeout = HZ; + tend = jiffies + timeout; + + while (stl_datastate(portp)) { + if (signal_pending(current)) + break; + msleep_interruptible(20); + if (time_after_eq(jiffies, tend)) + break; + } } /*****************************************************************************/ static void stl_close(struct tty_struct *tty, struct file *filp) { - stlport_t *portp; + struct stlport *portp; unsigned long flags; -#ifdef DEBUG - printk("stl_close(tty=%x,filp=%x)\n", (int) tty, (int) filp); -#endif + pr_debug("stl_close(tty=%p,filp=%p)\n", tty, filp); portp = tty->driver_data; - if (portp == (stlport_t *) NULL) + if (portp == NULL) return; - save_flags(flags); - cli(); + spin_lock_irqsave(&stallion_lock, flags); if (tty_hung_up_p(filp)) { - restore_flags(flags); + spin_unlock_irqrestore(&stallion_lock, flags); return; } if ((tty->count == 1) && (portp->refcount != 1)) portp->refcount = 1; if (portp->refcount-- > 1) { - restore_flags(flags); + spin_unlock_irqrestore(&stallion_lock, flags); return; } @@ -1179,57 +903,44 @@ static void stl_close(struct tty_struct *tty, struct file *filp) * (The sc26198 has no "end-of-data" interrupt only empty FIFO) */ tty->closing = 1; + + spin_unlock_irqrestore(&stallion_lock, flags); + if (portp->closing_wait != ASYNC_CLOSING_WAIT_NONE) tty_wait_until_sent(tty, portp->closing_wait); stl_waituntilsent(tty, (HZ / 2)); + + spin_lock_irqsave(&stallion_lock, flags); portp->flags &= ~ASYNC_INITIALIZED; + spin_unlock_irqrestore(&stallion_lock, flags); + stl_disableintrs(portp); if (tty->termios->c_cflag & HUPCL) stl_setsignals(portp, 0, 0); stl_enablerxtx(portp, 0, 0); stl_flushbuffer(tty); portp->istate = 0; - if (portp->tx.buf != (char *) NULL) { + if (portp->tx.buf != NULL) { kfree(portp->tx.buf); - portp->tx.buf = (char *) NULL; - portp->tx.head = (char *) NULL; - portp->tx.tail = (char *) NULL; + portp->tx.buf = NULL; + portp->tx.head = NULL; + portp->tx.tail = NULL; } set_bit(TTY_IO_ERROR, &tty->flags); tty_ldisc_flush(tty); tty->closing = 0; - portp->tty = (struct tty_struct *) NULL; + portp->tty = NULL; if (portp->openwaitcnt) { if (portp->close_delay) - stl_delay(portp->close_delay); + msleep_interruptible(jiffies_to_msecs(portp->close_delay)); wake_up_interruptible(&portp->open_wait); } portp->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&portp->close_wait); - restore_flags(flags); -} - -/*****************************************************************************/ - -/* - * Wait for a specified delay period, this is not a busy-loop. It will - * give up the processor while waiting. Unfortunately this has some - * rather intimate knowledge of the process management stuff. - */ - -static void stl_delay(int len) -{ -#ifdef DEBUG - printk("stl_delay(len=%d)\n", len); -#endif - if (len > 0) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(len); - } } /*****************************************************************************/ @@ -1239,26 +950,20 @@ static void stl_delay(int len) * If transmit interrupts are not running then start them. */ -static int stl_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count) +static int stl_write(struct tty_struct *tty, const unsigned char *buf, int count) { - stlport_t *portp; + struct stlport *portp; unsigned int len, stlen; unsigned char *chbuf; char *head, *tail; -#ifdef DEBUG - printk("stl_write(tty=%x,from_user=%d,buf=%x,count=%d)\n", - (int) tty, from_user, (int) buf, count); -#endif + pr_debug("stl_write(tty=%p,buf=%p,count=%d)\n", tty, buf, count); - if ((tty == (struct tty_struct *) NULL) || - (stl_tmpwritebuf == (char *) NULL)) - return(0); portp = tty->driver_data; - if (portp == (stlport_t *) NULL) - return(0); - if (portp->tx.buf == (char *) NULL) - return(0); + if (portp == NULL) + return 0; + if (portp->tx.buf == NULL) + return 0; /* * If copying direct from user space we must cater for page faults, @@ -1267,18 +972,6 @@ static int stl_write(struct tty_struct *tty, int from_user, const unsigned char * copy it into the TX buffer. */ chbuf = (unsigned char *) buf; - if (from_user) { - head = portp->tx.head; - tail = portp->tx.tail; - len = (head >= tail) ? (STL_TXBUFSIZE - (head - tail) - 1) : - (tail - head - 1); - count = MIN(len, count); - - down(&stl_tmpwritesem); - if (copy_from_user(stl_tmpwritebuf, chbuf, count)) - return -EFAULT; - chbuf = &stl_tmpwritebuf[0]; - } head = portp->tx.head; tail = portp->tx.tail; @@ -1290,10 +983,10 @@ static int stl_write(struct tty_struct *tty, int from_user, const unsigned char stlen = len; } - len = MIN(len, count); + len = min(len, (unsigned int)count); count = 0; while (len > 0) { - stlen = MIN(len, stlen); + stlen = min(len, stlen); memcpy(head, chbuf, stlen); len -= stlen; chbuf += stlen; @@ -1309,30 +1002,25 @@ static int stl_write(struct tty_struct *tty, int from_user, const unsigned char clear_bit(ASYI_TXLOW, &portp->istate); stl_startrxtx(portp, -1, 1); - if (from_user) - up(&stl_tmpwritesem); - - return(count); + return count; } /*****************************************************************************/ static void stl_putchar(struct tty_struct *tty, unsigned char ch) { - stlport_t *portp; + struct stlport *portp; unsigned int len; char *head, *tail; -#ifdef DEBUG - printk("stl_putchar(tty=%x,ch=%x)\n", (int) tty, (int) ch); -#endif + pr_debug("stl_putchar(tty=%p,ch=%x)\n", tty, ch); - if (tty == (struct tty_struct *) NULL) + if (tty == NULL) return; portp = tty->driver_data; - if (portp == (stlport_t *) NULL) + if (portp == NULL) return; - if (portp->tx.buf == (char *) NULL) + if (portp->tx.buf == NULL) return; head = portp->tx.head; @@ -1359,25 +1047,18 @@ static void stl_putchar(struct tty_struct *tty, unsigned char ch) static void stl_flushchars(struct tty_struct *tty) { - stlport_t *portp; + struct stlport *portp; -#ifdef DEBUG - printk("stl_flushchars(tty=%x)\n", (int) tty); -#endif + pr_debug("stl_flushchars(tty=%p)\n", tty); - if (tty == (struct tty_struct *) NULL) + if (tty == NULL) return; portp = tty->driver_data; - if (portp == (stlport_t *) NULL) + if (portp == NULL) return; - if (portp->tx.buf == (char *) NULL) + if (portp->tx.buf == NULL) return; -#if 0 - if (tty->stopped || tty->hw_stopped || - (portp->tx.head == portp->tx.tail)) - return; -#endif stl_startrxtx(portp, -1, 1); } @@ -1385,24 +1066,22 @@ static void stl_flushchars(struct tty_struct *tty) static int stl_writeroom(struct tty_struct *tty) { - stlport_t *portp; + struct stlport *portp; char *head, *tail; -#ifdef DEBUG - printk("stl_writeroom(tty=%x)\n", (int) tty); -#endif + pr_debug("stl_writeroom(tty=%p)\n", tty); - if (tty == (struct tty_struct *) NULL) - return(0); + if (tty == NULL) + return 0; portp = tty->driver_data; - if (portp == (stlport_t *) NULL) - return(0); - if (portp->tx.buf == (char *) NULL) - return(0); + if (portp == NULL) + return 0; + if (portp->tx.buf == NULL) + return 0; head = portp->tx.head; tail = portp->tx.tail; - return((head >= tail) ? (STL_TXBUFSIZE - (head - tail) - 1) : (tail - head - 1)); + return (head >= tail) ? (STL_TXBUFSIZE - (head - tail) - 1) : (tail - head - 1); } /*****************************************************************************/ @@ -1418,28 +1097,26 @@ static int stl_writeroom(struct tty_struct *tty) static int stl_charsinbuffer(struct tty_struct *tty) { - stlport_t *portp; + struct stlport *portp; unsigned int size; char *head, *tail; -#ifdef DEBUG - printk("stl_charsinbuffer(tty=%x)\n", (int) tty); -#endif + pr_debug("stl_charsinbuffer(tty=%p)\n", tty); - if (tty == (struct tty_struct *) NULL) - return(0); + if (tty == NULL) + return 0; portp = tty->driver_data; - if (portp == (stlport_t *) NULL) - return(0); - if (portp->tx.buf == (char *) NULL) - return(0); + if (portp == NULL) + return 0; + if (portp->tx.buf == NULL) + return 0; head = portp->tx.head; tail = portp->tx.tail; size = (head >= tail) ? (head - tail) : (STL_TXBUFSIZE - (tail - head)); if ((size == 0) && test_bit(ASYI_TXBUSY, &portp->istate)) size = 1; - return(size); + return size; } /*****************************************************************************/ @@ -1448,14 +1125,12 @@ static int stl_charsinbuffer(struct tty_struct *tty) * Generate the serial struct info. */ -static int stl_getserial(stlport_t *portp, struct serial_struct __user *sp) +static int stl_getserial(struct stlport *portp, struct serial_struct __user *sp) { struct serial_struct sio; - stlbrd_t *brdp; + struct stlbrd *brdp; -#ifdef DEBUG - printk("stl_getserial(portp=%x,sp=%x)\n", (int) portp, (int) sp); -#endif + pr_debug("stl_getserial(portp=%p,sp=%p)\n", portp, sp); memset(&sio, 0, sizeof(struct serial_struct)); sio.line = portp->portnr; @@ -1475,7 +1150,7 @@ static int stl_getserial(stlport_t *portp, struct serial_struct __user *sp) } brdp = stl_brds[portp->brdnr]; - if (brdp != (stlbrd_t *) NULL) + if (brdp != NULL) sio.irq = brdp->irq; return copy_to_user(sp, &sio, sizeof(struct serial_struct)) ? -EFAULT : 0; @@ -1489,13 +1164,11 @@ static int stl_getserial(stlport_t *portp, struct serial_struct __user *sp) * just quietly ignore any requests to change irq, etc. */ -static int stl_setserial(stlport_t *portp, struct serial_struct __user *sp) +static int stl_setserial(struct stlport *portp, struct serial_struct __user *sp) { struct serial_struct sio; -#ifdef DEBUG - printk("stl_setserial(portp=%x,sp=%x)\n", (int) portp, (int) sp); -#endif + pr_debug("stl_setserial(portp=%p,sp=%p)\n", portp, sp); if (copy_from_user(&sio, sp, sizeof(struct serial_struct))) return -EFAULT; @@ -1504,7 +1177,7 @@ static int stl_setserial(stlport_t *portp, struct serial_struct __user *sp) (sio.close_delay != portp->close_delay) || ((sio.flags & ~ASYNC_USR_MASK) != (portp->flags & ~ASYNC_USR_MASK))) - return(-EPERM); + return -EPERM; } portp->flags = (portp->flags & ~ASYNC_USR_MASK) | @@ -1514,22 +1187,22 @@ static int stl_setserial(stlport_t *portp, struct serial_struct __user *sp) portp->closing_wait = sio.closing_wait; portp->custom_divisor = sio.custom_divisor; stl_setport(portp, portp->tty->termios); - return(0); + return 0; } /*****************************************************************************/ static int stl_tiocmget(struct tty_struct *tty, struct file *file) { - stlport_t *portp; + struct stlport *portp; - if (tty == (struct tty_struct *) NULL) - return(-ENODEV); + if (tty == NULL) + return -ENODEV; portp = tty->driver_data; - if (portp == (stlport_t *) NULL) - return(-ENODEV); + if (portp == NULL) + return -ENODEV; if (tty->flags & (1 << TTY_IO_ERROR)) - return(-EIO); + return -EIO; return stl_getsignals(portp); } @@ -1537,16 +1210,16 @@ static int stl_tiocmget(struct tty_struct *tty, struct file *file) static int stl_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear) { - stlport_t *portp; + struct stlport *portp; int rts = -1, dtr = -1; - if (tty == (struct tty_struct *) NULL) - return(-ENODEV); + if (tty == NULL) + return -ENODEV; portp = tty->driver_data; - if (portp == (stlport_t *) NULL) - return(-ENODEV); + if (portp == NULL) + return -ENODEV; if (tty->flags & (1 << TTY_IO_ERROR)) - return(-EIO); + return -EIO; if (set & TIOCM_RTS) rts = 1; @@ -1563,27 +1236,24 @@ static int stl_tiocmset(struct tty_struct *tty, struct file *file, static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { - stlport_t *portp; + struct stlport *portp; unsigned int ival; int rc; void __user *argp = (void __user *)arg; -#ifdef DEBUG - printk("stl_ioctl(tty=%x,file=%x,cmd=%x,arg=%x)\n", - (int) tty, (int) file, cmd, (int) arg); -#endif + pr_debug("stl_ioctl(tty=%p,file=%p,cmd=%x,arg=%lx)\n", tty, file, cmd, + arg); - if (tty == (struct tty_struct *) NULL) - return(-ENODEV); + if (tty == NULL) + return -ENODEV; portp = tty->driver_data; - if (portp == (stlport_t *) NULL) - return(-ENODEV); + if (portp == NULL) + return -ENODEV; if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && - (cmd != COM_GETPORTSTATS) && (cmd != COM_CLRPORTSTATS)) { + (cmd != COM_GETPORTSTATS) && (cmd != COM_CLRPORTSTATS)) if (tty->flags & (1 << TTY_IO_ERROR)) - return(-EIO); - } + return -EIO; rc = 0; @@ -1623,24 +1293,42 @@ static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd break; } - return(rc); + return rc; } /*****************************************************************************/ -static void stl_settermios(struct tty_struct *tty, struct termios *old) +/* + * Start the transmitter again. Just turn TX interrupts back on. + */ + +static void stl_start(struct tty_struct *tty) { - stlport_t *portp; - struct termios *tiosp; + struct stlport *portp; -#ifdef DEBUG - printk("stl_settermios(tty=%x,old=%x)\n", (int) tty, (int) old); -#endif + pr_debug("stl_start(tty=%p)\n", tty); + + if (tty == NULL) + return; + portp = tty->driver_data; + if (portp == NULL) + return; + stl_startrxtx(portp, -1, 1); +} + +/*****************************************************************************/ + +static void stl_settermios(struct tty_struct *tty, struct ktermios *old) +{ + struct stlport *portp; + struct ktermios *tiosp; + + pr_debug("stl_settermios(tty=%p,old=%p)\n", tty, old); - if (tty == (struct tty_struct *) NULL) + if (tty == NULL) return; portp = tty->driver_data; - if (portp == (stlport_t *) NULL) + if (portp == NULL) return; tiosp = tty->termios; @@ -1668,16 +1356,14 @@ static void stl_settermios(struct tty_struct *tty, struct termios *old) static void stl_throttle(struct tty_struct *tty) { - stlport_t *portp; + struct stlport *portp; -#ifdef DEBUG - printk("stl_throttle(tty=%x)\n", (int) tty); -#endif + pr_debug("stl_throttle(tty=%p)\n", tty); - if (tty == (struct tty_struct *) NULL) + if (tty == NULL) return; portp = tty->driver_data; - if (portp == (stlport_t *) NULL) + if (portp == NULL) return; stl_flowctrl(portp, 0); } @@ -1690,16 +1376,14 @@ static void stl_throttle(struct tty_struct *tty) static void stl_unthrottle(struct tty_struct *tty) { - stlport_t *portp; + struct stlport *portp; -#ifdef DEBUG - printk("stl_unthrottle(tty=%x)\n", (int) tty); -#endif + pr_debug("stl_unthrottle(tty=%p)\n", tty); - if (tty == (struct tty_struct *) NULL) + if (tty == NULL) return; portp = tty->driver_data; - if (portp == (stlport_t *) NULL) + if (portp == NULL) return; stl_flowctrl(portp, 1); } @@ -1713,44 +1397,20 @@ static void stl_unthrottle(struct tty_struct *tty) static void stl_stop(struct tty_struct *tty) { - stlport_t *portp; + struct stlport *portp; -#ifdef DEBUG - printk("stl_stop(tty=%x)\n", (int) tty); -#endif + pr_debug("stl_stop(tty=%p)\n", tty); - if (tty == (struct tty_struct *) NULL) + if (tty == NULL) return; portp = tty->driver_data; - if (portp == (stlport_t *) NULL) + if (portp == NULL) return; stl_startrxtx(portp, -1, 0); } /*****************************************************************************/ -/* - * Start the transmitter again. Just turn TX interrupts back on. - */ - -static void stl_start(struct tty_struct *tty) -{ - stlport_t *portp; - -#ifdef DEBUG - printk("stl_start(tty=%x)\n", (int) tty); -#endif - - if (tty == (struct tty_struct *) NULL) - return; - portp = tty->driver_data; - if (portp == (stlport_t *) NULL) - return; - stl_startrxtx(portp, -1, 1); -} - -/*****************************************************************************/ - /* * Hangup this port. This is pretty much like closing the port, only * a little more brutal. No waiting for data to drain. Shutdown the @@ -1759,16 +1419,14 @@ static void stl_start(struct tty_struct *tty) static void stl_hangup(struct tty_struct *tty) { - stlport_t *portp; + struct stlport *portp; -#ifdef DEBUG - printk("stl_hangup(tty=%x)\n", (int) tty); -#endif + pr_debug("stl_hangup(tty=%p)\n", tty); - if (tty == (struct tty_struct *) NULL) + if (tty == NULL) return; portp = tty->driver_data; - if (portp == (stlport_t *) NULL) + if (portp == NULL) return; portp->flags &= ~ASYNC_INITIALIZED; @@ -1779,13 +1437,13 @@ static void stl_hangup(struct tty_struct *tty) stl_flushbuffer(tty); portp->istate = 0; set_bit(TTY_IO_ERROR, &tty->flags); - if (portp->tx.buf != (char *) NULL) { + if (portp->tx.buf != NULL) { kfree(portp->tx.buf); - portp->tx.buf = (char *) NULL; - portp->tx.head = (char *) NULL; - portp->tx.tail = (char *) NULL; + portp->tx.buf = NULL; + portp->tx.head = NULL; + portp->tx.tail = NULL; } - portp->tty = (struct tty_struct *) NULL; + portp->tty = NULL; portp->flags &= ~ASYNC_NORMAL_ACTIVE; portp->refcount = 0; wake_up_interruptible(&portp->open_wait); @@ -1793,38 +1451,16 @@ static void stl_hangup(struct tty_struct *tty) /*****************************************************************************/ -static void stl_flushbuffer(struct tty_struct *tty) -{ - stlport_t *portp; - -#ifdef DEBUG - printk("stl_flushbuffer(tty=%x)\n", (int) tty); -#endif - - if (tty == (struct tty_struct *) NULL) - return; - portp = tty->driver_data; - if (portp == (stlport_t *) NULL) - return; - - stl_flush(portp); - tty_wakeup(tty); -} - -/*****************************************************************************/ - static void stl_breakctl(struct tty_struct *tty, int state) { - stlport_t *portp; + struct stlport *portp; -#ifdef DEBUG - printk("stl_breakctl(tty=%x,state=%d)\n", (int) tty, state); -#endif + pr_debug("stl_breakctl(tty=%p,state=%d)\n", tty, state); - if (tty == (struct tty_struct *) NULL) + if (tty == NULL) return; portp = tty->driver_data; - if (portp == (stlport_t *) NULL) + if (portp == NULL) return; stl_sendbreak(portp, ((state == -1) ? 1 : 2)); @@ -1832,48 +1468,16 @@ static void stl_breakctl(struct tty_struct *tty, int state) /*****************************************************************************/ -static void stl_waituntilsent(struct tty_struct *tty, int timeout) -{ - stlport_t *portp; - unsigned long tend; - -#ifdef DEBUG - printk("stl_waituntilsent(tty=%x,timeout=%d)\n", (int) tty, timeout); -#endif - - if (tty == (struct tty_struct *) NULL) - return; - portp = tty->driver_data; - if (portp == (stlport_t *) NULL) - return; - - if (timeout == 0) - timeout = HZ; - tend = jiffies + timeout; - - while (stl_datastate(portp)) { - if (signal_pending(current)) - break; - stl_delay(2); - if (time_after_eq(jiffies, tend)) - break; - } -} - -/*****************************************************************************/ - static void stl_sendxchar(struct tty_struct *tty, char ch) { - stlport_t *portp; + struct stlport *portp; -#ifdef DEBUG - printk("stl_sendxchar(tty=%x,ch=%x)\n", (int) tty, ch); -#endif + pr_debug("stl_sendxchar(tty=%p,ch=%x)\n", tty, ch); - if (tty == (struct tty_struct *) NULL) + if (tty == NULL) return; portp = tty->driver_data; - if (portp == (stlport_t *) NULL) + if (portp == NULL) return; if (ch == STOP_CHAR(tty)) @@ -1894,7 +1498,7 @@ static void stl_sendxchar(struct tty_struct *tty, char ch) * short then padded with spaces). */ -static int stl_portinfo(stlport_t *portp, int portnr, char *pos) +static int stl_portinfo(struct stlport *portp, int portnr, char *pos) { char *sp; int sigs, cnt; @@ -1923,13 +1527,13 @@ static int stl_portinfo(stlport_t *portp, int portnr, char *pos) *sp = ' '; sp += cnt; - for (cnt = (sp - pos); (cnt < (MAXLINE - 1)); cnt++) + for (cnt = sp - pos; cnt < (MAXLINE - 1); cnt++) *sp++ = ' '; if (cnt >= MAXLINE) pos[(MAXLINE - 2)] = '+'; pos[(MAXLINE - 1)] = '\n'; - return(MAXLINE); + return MAXLINE; } /*****************************************************************************/ @@ -1940,18 +1544,15 @@ static int stl_portinfo(stlport_t *portp, int portnr, char *pos) static int stl_readproc(char *page, char **start, off_t off, int count, int *eof, void *data) { - stlbrd_t *brdp; - stlpanel_t *panelp; - stlport_t *portp; - int brdnr, panelnr, portnr, totalport; - int curoff, maxoff; + struct stlbrd *brdp; + struct stlpanel *panelp; + struct stlport *portp; + unsigned int brdnr, panelnr, portnr; + int totalport, curoff, maxoff; char *pos; -#ifdef DEBUG - printk("stl_readproc(page=%x,start=%x,off=%x,count=%d,eof=%x," - "data=%x\n", (int) page, (int) start, (int) off, count, - (int) eof, (int) data); -#endif + pr_debug("stl_readproc(page=%p,start=%p,off=%lx,count=%d,eof=%p," + "data=%p\n", page, start, off, count, eof, data); pos = page; totalport = 0; @@ -1970,9 +1571,9 @@ static int stl_readproc(char *page, char **start, off_t off, int count, int *eof * We scan through for each board, panel and port. The offset is * calculated on the fly, and irrelevant ports are skipped. */ - for (brdnr = 0; (brdnr < stl_nrbrds); brdnr++) { + for (brdnr = 0; brdnr < stl_nrbrds; brdnr++) { brdp = stl_brds[brdnr]; - if (brdp == (stlbrd_t *) NULL) + if (brdp == NULL) continue; if (brdp->state == 0) continue; @@ -1984,9 +1585,9 @@ static int stl_readproc(char *page, char **start, off_t off, int count, int *eof } totalport = brdnr * STL_MAXPORTS; - for (panelnr = 0; (panelnr < brdp->nrpanels); panelnr++) { + for (panelnr = 0; panelnr < brdp->nrpanels; panelnr++) { panelp = brdp->panels[panelnr]; - if (panelp == (stlpanel_t *) NULL) + if (panelp == NULL) continue; maxoff = curoff + (panelp->nrports * MAXLINE); @@ -1996,10 +1597,10 @@ static int stl_readproc(char *page, char **start, off_t off, int count, int *eof continue; } - for (portnr = 0; (portnr < panelp->nrports); portnr++, + for (portnr = 0; portnr < panelp->nrports; portnr++, totalport++) { portp = panelp->ports[portnr]; - if (portp == (stlport_t *) NULL) + if (portp == NULL) continue; if (off >= (curoff += MAXLINE)) continue; @@ -2014,7 +1615,7 @@ static int stl_readproc(char *page, char **start, off_t off, int count, int *eof stl_readdone: *start = page; - return(pos - page); + return pos - page; } /*****************************************************************************/ @@ -2024,25 +1625,13 @@ stl_readdone: * calls off to the approrpriate board interrupt handlers. */ -static irqreturn_t stl_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t stl_intr(int irq, void *dev_id) { - stlbrd_t *brdp; - int i; - int handled = 0; + struct stlbrd *brdp = dev_id; -#ifdef DEBUG - printk("stl_intr(irq=%d,regs=%x)\n", irq, (int) regs); -#endif + pr_debug("stl_intr(brdp=%p,irq=%d)\n", brdp, irq); - for (i = 0; (i < stl_nrbrds); i++) { - if ((brdp = stl_brds[i]) == (stlbrd_t *) NULL) - continue; - if (brdp->state == 0) - continue; - handled = 1; - (* brdp->isr)(brdp); - } - return IRQ_RETVAL(handled); + return IRQ_RETVAL((* brdp->isr)(brdp)); } /*****************************************************************************/ @@ -2051,15 +1640,21 @@ static irqreturn_t stl_intr(int irq, void *dev_id, struct pt_regs *regs) * Interrupt service routine for EasyIO board types. */ -static void stl_eiointr(stlbrd_t *brdp) +static int stl_eiointr(struct stlbrd *brdp) { - stlpanel_t *panelp; + struct stlpanel *panelp; unsigned int iobase; + int handled = 0; + spin_lock(&brd_lock); panelp = brdp->panels[0]; iobase = panelp->iobase; - while (inb(brdp->iostatus) & EIO_INTRPEND) + while (inb(brdp->iostatus) & EIO_INTRPEND) { + handled = 1; (* panelp->isr)(panelp, iobase); + } + spin_unlock(&brd_lock); + return handled; } /*****************************************************************************/ @@ -2068,16 +1663,17 @@ static void stl_eiointr(stlbrd_t *brdp) * Interrupt service routine for ECH-AT board types. */ -static void stl_echatintr(stlbrd_t *brdp) +static int stl_echatintr(struct stlbrd *brdp) { - stlpanel_t *panelp; - unsigned int ioaddr; - int bnknr; + struct stlpanel *panelp; + unsigned int ioaddr, bnknr; + int handled = 0; outb((brdp->ioctrlval | ECH_BRDENABLE), brdp->ioctrl); while (inb(brdp->iostatus) & ECH_INTRPEND) { - for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) { + handled = 1; + for (bnknr = 0; bnknr < brdp->nrbnks; bnknr++) { ioaddr = brdp->bnkstataddr[bnknr]; if (inb(ioaddr) & ECH_PNLINTRPEND) { panelp = brdp->bnk2panel[bnknr]; @@ -2087,6 +1683,8 @@ static void stl_echatintr(stlbrd_t *brdp) } outb((brdp->ioctrlval | ECH_BRDDISABLE), brdp->ioctrl); + + return handled; } /*****************************************************************************/ @@ -2095,14 +1693,15 @@ static void stl_echatintr(stlbrd_t *brdp) * Interrupt service routine for ECH-MCA board types. */ -static void stl_echmcaintr(stlbrd_t *brdp) +static int stl_echmcaintr(struct stlbrd *brdp) { - stlpanel_t *panelp; - unsigned int ioaddr; - int bnknr; + struct stlpanel *panelp; + unsigned int ioaddr, bnknr; + int handled = 0; while (inb(brdp->iostatus) & ECH_INTRPEND) { - for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) { + handled = 1; + for (bnknr = 0; bnknr < brdp->nrbnks; bnknr++) { ioaddr = brdp->bnkstataddr[bnknr]; if (inb(ioaddr) & ECH_PNLINTRPEND) { panelp = brdp->bnk2panel[bnknr]; @@ -2110,6 +1709,7 @@ static void stl_echmcaintr(stlbrd_t *brdp) } } } + return handled; } /*****************************************************************************/ @@ -2118,26 +1718,28 @@ static void stl_echmcaintr(stlbrd_t *brdp) * Interrupt service routine for ECH-PCI board types. */ -static void stl_echpciintr(stlbrd_t *brdp) +static int stl_echpciintr(struct stlbrd *brdp) { - stlpanel_t *panelp; - unsigned int ioaddr; - int bnknr, recheck; + struct stlpanel *panelp; + unsigned int ioaddr, bnknr, recheck; + int handled = 0; while (1) { recheck = 0; - for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) { + for (bnknr = 0; bnknr < brdp->nrbnks; bnknr++) { outb(brdp->bnkpageaddr[bnknr], brdp->ioctrl); ioaddr = brdp->bnkstataddr[bnknr]; if (inb(ioaddr) & ECH_PNLINTRPEND) { panelp = brdp->bnk2panel[bnknr]; (* panelp->isr)(panelp, (ioaddr & 0xfffc)); recheck++; + handled = 1; } } if (! recheck) break; } + return handled; } /*****************************************************************************/ @@ -2146,14 +1748,15 @@ static void stl_echpciintr(stlbrd_t *brdp) * Interrupt service routine for ECH-8/64-PCI board types. */ -static void stl_echpci64intr(stlbrd_t *brdp) +static int stl_echpci64intr(struct stlbrd *brdp) { - stlpanel_t *panelp; - unsigned int ioaddr; - int bnknr; + struct stlpanel *panelp; + unsigned int ioaddr, bnknr; + int handled = 0; while (inb(brdp->ioctrl) & 0x1) { - for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) { + handled = 1; + for (bnknr = 0; bnknr < brdp->nrbnks; bnknr++) { ioaddr = brdp->bnkstataddr[bnknr]; if (inb(ioaddr) & ECH_PNLINTRPEND) { panelp = brdp->bnk2panel[bnknr]; @@ -2161,6 +1764,8 @@ static void stl_echpci64intr(stlbrd_t *brdp) } } } + + return handled; } /*****************************************************************************/ @@ -2168,90 +1773,51 @@ static void stl_echpci64intr(stlbrd_t *brdp) /* * Service an off-level request for some channel. */ -static void stl_offintr(void *private) +static void stl_offintr(struct work_struct *work) { - stlport_t *portp; + struct stlport *portp = container_of(work, struct stlport, tqueue); struct tty_struct *tty; unsigned int oldsigs; - portp = private; - -#ifdef DEBUG - printk("stl_offintr(portp=%x)\n", (int) portp); -#endif + pr_debug("stl_offintr(portp=%p)\n", portp); - if (portp == (stlport_t *) NULL) + if (portp == NULL) return; tty = portp->tty; - if (tty == (struct tty_struct *) NULL) + if (tty == NULL) return; lock_kernel(); - if (test_bit(ASYI_TXLOW, &portp->istate)) { + if (test_bit(ASYI_TXLOW, &portp->istate)) tty_wakeup(tty); - } + if (test_bit(ASYI_DCDCHANGE, &portp->istate)) { clear_bit(ASYI_DCDCHANGE, &portp->istate); oldsigs = portp->sigs; portp->sigs = stl_getsignals(portp); if ((portp->sigs & TIOCM_CD) && ((oldsigs & TIOCM_CD) == 0)) wake_up_interruptible(&portp->open_wait); - if ((oldsigs & TIOCM_CD) && ((portp->sigs & TIOCM_CD) == 0)) { + if ((oldsigs & TIOCM_CD) && ((portp->sigs & TIOCM_CD) == 0)) if (portp->flags & ASYNC_CHECK_CD) tty_hangup(tty); /* FIXME: module removal race here - AKPM */ - } } unlock_kernel(); } /*****************************************************************************/ -/* - * Map in interrupt vector to this driver. Check that we don't - * already have this vector mapped, we might be sharing this - * interrupt across multiple boards. - */ - -static int __init stl_mapirq(int irq, char *name) -{ - int rc, i; - -#ifdef DEBUG - printk("stl_mapirq(irq=%d,name=%s)\n", irq, name); -#endif - - rc = 0; - for (i = 0; (i < stl_numintrs); i++) { - if (stl_gotintrs[i] == irq) - break; - } - if (i >= stl_numintrs) { - if (request_irq(irq, stl_intr, SA_SHIRQ, name, NULL) != 0) { - printk("STALLION: failed to register interrupt " - "routine for %s irq=%d\n", name, irq); - rc = -ENODEV; - } else { - stl_gotintrs[stl_numintrs++] = irq; - } - } - return(rc); -} - -/*****************************************************************************/ - /* * Initialize all the ports on a panel. */ -static int __init stl_initports(stlbrd_t *brdp, stlpanel_t *panelp) +static int __devinit stl_initports(struct stlbrd *brdp, struct stlpanel *panelp) { - stlport_t *portp; - int chipmask, i; + struct stlport *portp; + unsigned int i; + int chipmask; -#ifdef DEBUG - printk("stl_initports(brdp=%x,panelp=%x)\n", (int) brdp, (int) panelp); -#endif + pr_debug("stl_initports(brdp=%p,panelp=%p)\n", brdp, panelp); chipmask = stl_panelinit(brdp, panelp); @@ -2259,14 +1825,13 @@ static int __init stl_initports(stlbrd_t *brdp, stlpanel_t *panelp) * All UART's are initialized (if found!). Now go through and setup * each ports data structures. */ - for (i = 0; (i < panelp->nrports); i++) { - portp = (stlport_t *) stl_memalloc(sizeof(stlport_t)); - if (portp == (stlport_t *) NULL) { + for (i = 0; i < panelp->nrports; i++) { + portp = kzalloc(sizeof(struct stlport), GFP_KERNEL); + if (!portp) { printk("STALLION: failed to allocate memory " - "(size=%d)\n", sizeof(stlport_t)); + "(size=%Zd)\n", sizeof(struct stlport)); break; } - memset(portp, 0, sizeof(stlport_t)); portp->magic = STL_PORTMAGIC; portp->portnr = i; @@ -2277,7 +1842,7 @@ static int __init stl_initports(stlbrd_t *brdp, stlpanel_t *panelp) portp->baud_base = STL_BAUDBASE; portp->close_delay = STL_CLOSEDELAY; portp->closing_wait = 30 * HZ; - INIT_WORK(&portp->tqueue, stl_offintr, portp); + INIT_WORK(&portp->tqueue, stl_offintr); init_waitqueue_head(&portp->open_wait); init_waitqueue_head(&portp->close_wait); portp->stats.brd = portp->brdnr; @@ -2287,7 +1852,30 @@ static int __init stl_initports(stlbrd_t *brdp, stlpanel_t *panelp) stl_portinit(brdp, panelp, portp); } - return(0); + return 0; +} + +static void stl_cleanup_panels(struct stlbrd *brdp) +{ + struct stlpanel *panelp; + struct stlport *portp; + unsigned int j, k; + + for (j = 0; j < STL_MAXPANELS; j++) { + panelp = brdp->panels[j]; + if (panelp == NULL) + continue; + for (k = 0; k < STL_PORTSPERPANEL; k++) { + portp = panelp->ports[k]; + if (portp == NULL) + continue; + if (portp->tty != NULL) + stl_hangup(portp->tty); + kfree(portp->tx.buf); + kfree(portp); + } + kfree(panelp); + } } /*****************************************************************************/ @@ -2296,16 +1884,14 @@ static int __init stl_initports(stlbrd_t *brdp, stlpanel_t *panelp) * Try to find and initialize an EasyIO board. */ -static inline int stl_initeio(stlbrd_t *brdp) +static int __devinit stl_initeio(struct stlbrd *brdp) { - stlpanel_t *panelp; + struct stlpanel *panelp; unsigned int status; char *name; - int rc; + int retval; -#ifdef DEBUG - printk("stl_initeio(brdp=%x)\n", (int) brdp); -#endif + pr_debug("stl_initeio(brdp=%p)\n", brdp); brdp->ioctrl = brdp->ioaddr1 + 1; brdp->iostatus = brdp->ioaddr1 + 2; @@ -2330,18 +1916,20 @@ static inline int stl_initeio(stlbrd_t *brdp) (stl_vecmap[brdp->irq] == (unsigned char) 0xff)) { printk("STALLION: invalid irq=%d for brd=%d\n", brdp->irq, brdp->brdnr); - return(-EINVAL); + retval = -EINVAL; + goto err; } outb((stl_vecmap[brdp->irq] | EIO_0WS | ((brdp->irqtype) ? EIO_INTLEVEL : EIO_INTEDGE)), brdp->ioctrl); } + retval = -EBUSY; if (!request_region(brdp->ioaddr1, brdp->iosize1, name)) { printk(KERN_WARNING "STALLION: Warning, board %d I/O address " "%x conflicts with another device\n", brdp->brdnr, brdp->ioaddr1); - return(-EBUSY); + goto err; } if (brdp->iosize2 > 0) @@ -2352,8 +1940,7 @@ static inline int stl_initeio(stlbrd_t *brdp) printk(KERN_WARNING "STALLION: Warning, also " "releasing board %d I/O address %x \n", brdp->brdnr, brdp->ioaddr1); - release_region(brdp->ioaddr1, brdp->iosize1); - return(-EBUSY); + goto err_rel1; } /* @@ -2362,6 +1949,7 @@ static inline int stl_initeio(stlbrd_t *brdp) brdp->clk = CD1400_CLK; brdp->isr = stl_eiointr; + retval = -ENODEV; switch (status & EIO_IDBITMASK) { case EIO_8PORTM: brdp->clk = CD1400_CLK8M; @@ -2385,11 +1973,11 @@ static inline int stl_initeio(stlbrd_t *brdp) brdp->nrports = 16; break; default: - return(-ENODEV); + goto err_rel2; } break; default: - return(-ENODEV); + goto err_rel2; } /* @@ -2397,13 +1985,13 @@ static inline int stl_initeio(stlbrd_t *brdp) * can complete the setup. */ - panelp = (stlpanel_t *) stl_memalloc(sizeof(stlpanel_t)); - if (panelp == (stlpanel_t *) NULL) { + panelp = kzalloc(sizeof(struct stlpanel), GFP_KERNEL); + if (!panelp) { printk(KERN_WARNING "STALLION: failed to allocate memory " - "(size=%d)\n", sizeof(stlpanel_t)); - return(-ENOMEM); + "(size=%Zd)\n", sizeof(struct stlpanel)); + retval = -ENOMEM; + goto err_rel2; } - memset(panelp, 0, sizeof(stlpanel_t)); panelp->magic = STL_PANELMAGIC; panelp->brdnr = brdp->brdnr; @@ -2412,10 +2000,10 @@ static inline int stl_initeio(stlbrd_t *brdp) panelp->iobase = brdp->ioaddr1; panelp->hwid = status; if ((status & EIO_IDBITMASK) == EIO_MK3) { - panelp->uartp = (void *) &stl_sc26198uart; + panelp->uartp = &stl_sc26198uart; panelp->isr = stl_sc26198intr; } else { - panelp->uartp = (void *) &stl_cd1400uart; + panelp->uartp = &stl_cd1400uart; panelp->isr = stl_cd1400eiointr; } @@ -2423,8 +2011,23 @@ static inline int stl_initeio(stlbrd_t *brdp) brdp->nrpanels = 1; brdp->state |= BRD_FOUND; brdp->hwid = status; - rc = stl_mapirq(brdp->irq, name); - return(rc); + if (request_irq(brdp->irq, stl_intr, IRQF_SHARED, name, brdp) != 0) { + printk("STALLION: failed to register interrupt " + "routine for %s irq=%d\n", name, brdp->irq); + retval = -ENODEV; + goto err_fr; + } + + return 0; +err_fr: + stl_cleanup_panels(brdp); +err_rel2: + if (brdp->iosize2 > 0) + release_region(brdp->ioaddr2, brdp->iosize2); +err_rel1: + release_region(brdp->ioaddr1, brdp->iosize1); +err: + return retval; } /*****************************************************************************/ @@ -2434,16 +2037,14 @@ static inline int stl_initeio(stlbrd_t *brdp) * dealing with all types of ECH board. */ -static inline int stl_initech(stlbrd_t *brdp) +static int __devinit stl_initech(struct stlbrd *brdp) { - stlpanel_t *panelp; - unsigned int status, nxtid, ioaddr, conflict; - int panelnr, banknr, i; + struct stlpanel *panelp; + unsigned int status, nxtid, ioaddr, conflict, panelnr, banknr, i; + int retval; char *name; -#ifdef DEBUG - printk("stl_initech(brdp=%x)\n", (int) brdp); -#endif + pr_debug("stl_initech(brdp=%p)\n", brdp); status = 0; conflict = 0; @@ -2460,20 +2061,23 @@ static inline int stl_initech(stlbrd_t *brdp) brdp->ioctrl = brdp->ioaddr1 + 1; brdp->iostatus = brdp->ioaddr1 + 1; status = inb(brdp->iostatus); - if ((status & ECH_IDBITMASK) != ECH_ID) - return(-ENODEV); + if ((status & ECH_IDBITMASK) != ECH_ID) { + retval = -ENODEV; + goto err; + } if ((brdp->irq < 0) || (brdp->irq > 15) || (stl_vecmap[brdp->irq] == (unsigned char) 0xff)) { printk("STALLION: invalid irq=%d for brd=%d\n", brdp->irq, brdp->brdnr); - return(-EINVAL); + retval = -EINVAL; + goto err; } status = ((brdp->ioaddr2 & ECH_ADDR2MASK) >> 1); status |= (stl_vecmap[brdp->irq] << 1); outb((status | ECH_BRDRESET), brdp->ioaddr1); brdp->ioctrlval = ECH_INTENABLE | ((brdp->irqtype) ? ECH_INTLEVEL : ECH_INTEDGE); - for (i = 0; (i < 10); i++) + for (i = 0; i < 10; i++) outb((brdp->ioctrlval | ECH_BRDENABLE), brdp->ioctrl); brdp->iosize1 = 2; brdp->iosize2 = 32; @@ -2486,13 +2090,16 @@ static inline int stl_initech(stlbrd_t *brdp) brdp->ioctrl = brdp->ioaddr1 + 0x20; brdp->iostatus = brdp->ioctrl; status = inb(brdp->iostatus); - if ((status & ECH_IDBITMASK) != ECH_ID) - return(-ENODEV); + if ((status & ECH_IDBITMASK) != ECH_ID) { + retval = -ENODEV; + goto err; + } if ((brdp->irq < 0) || (brdp->irq > 15) || (stl_vecmap[brdp->irq] == (unsigned char) 0xff)) { printk("STALLION: invalid irq=%d for brd=%d\n", brdp->irq, brdp->brdnr); - return(-EINVAL); + retval = -EINVAL; + goto err; } outb(ECHMC_BRDRESET, brdp->ioctrl); outb(ECHMC_INTENABLE, brdp->ioctrl); @@ -2519,19 +2126,20 @@ static inline int stl_initech(stlbrd_t *brdp) default: printk("STALLION: unknown board type=%d\n", brdp->brdtype); - return(-EINVAL); - break; + retval = -EINVAL; + goto err; } /* * Check boards for possible IO address conflicts and return fail status * if an IO conflict found. */ + retval = -EBUSY; if (!request_region(brdp->ioaddr1, brdp->iosize1, name)) { printk(KERN_WARNING "STALLION: Warning, board %d I/O address " "%x conflicts with another device\n", brdp->brdnr, brdp->ioaddr1); - return(-EBUSY); + goto err; } if (brdp->iosize2 > 0) @@ -2542,8 +2150,7 @@ static inline int stl_initech(stlbrd_t *brdp) printk(KERN_WARNING "STALLION: Warning, also " "releasing board %d I/O address %x \n", brdp->brdnr, brdp->ioaddr1); - release_region(brdp->ioaddr1, brdp->iosize1); - return(-EBUSY); + goto err_rel1; } /* @@ -2558,21 +2165,20 @@ static inline int stl_initech(stlbrd_t *brdp) panelnr = 0; nxtid = 0; - for (i = 0; (i < STL_MAXPANELS); i++) { + for (i = 0; i < STL_MAXPANELS; i++) { if (brdp->brdtype == BRD_ECHPCI) { outb(nxtid, brdp->ioctrl); ioaddr = brdp->ioaddr2; } status = inb(ioaddr + ECH_PNLSTATUS); if ((status & ECH_PNLIDMASK) != nxtid) - break; - panelp = (stlpanel_t *) stl_memalloc(sizeof(stlpanel_t)); - if (panelp == (stlpanel_t *) NULL) { + goto err_fr; + panelp = kzalloc(sizeof(struct stlpanel), GFP_KERNEL); + if (!panelp) { printk("STALLION: failed to allocate memory " - "(size=%d)\n", sizeof(stlpanel_t)); - break; + "(size=%Zd)\n", sizeof(struct stlpanel)); + goto err_fr; } - memset(panelp, 0, sizeof(stlpanel_t)); panelp->magic = STL_PANELMAGIC; panelp->brdnr = brdp->brdnr; panelp->panelnr = panelnr; @@ -2584,7 +2190,7 @@ static inline int stl_initech(stlbrd_t *brdp) brdp->bnkstataddr[banknr++] = ioaddr + ECH_PNLSTATUS; if (status & ECH_PNLXPID) { - panelp->uartp = (void *) &stl_sc26198uart; + panelp->uartp = &stl_sc26198uart; panelp->isr = stl_sc26198intr; if (status & ECH_PNL16PORT) { panelp->nrports = 16; @@ -2592,11 +2198,10 @@ static inline int stl_initech(stlbrd_t *brdp) brdp->bnkpageaddr[banknr] = nxtid; brdp->bnkstataddr[banknr++] = ioaddr + 4 + ECH_PNLSTATUS; - } else { + } else panelp->nrports = 8; - } } else { - panelp->uartp = (void *) &stl_cd1400uart; + panelp->uartp = &stl_cd1400uart; panelp->isr = stl_cd1400echintr; if (status & ECH_PNL16PORT) { panelp->nrports = 16; @@ -2619,7 +2224,7 @@ static inline int stl_initech(stlbrd_t *brdp) brdp->panels[panelnr++] = panelp; if ((brdp->brdtype != BRD_ECHPCI) && (ioaddr >= (brdp->ioaddr2 + brdp->iosize2))) - break; + goto err_fr; } brdp->nrpanels = panelnr; @@ -2628,8 +2233,22 @@ static inline int stl_initech(stlbrd_t *brdp) outb((brdp->ioctrlval | ECH_BRDDISABLE), brdp->ioctrl); brdp->state |= BRD_FOUND; - i = stl_mapirq(brdp->irq, name); - return(i); + if (request_irq(brdp->irq, stl_intr, IRQF_SHARED, name, brdp) != 0) { + printk("STALLION: failed to register interrupt " + "routine for %s irq=%d\n", name, brdp->irq); + retval = -ENODEV; + goto err_fr; + } + + return 0; +err_fr: + stl_cleanup_panels(brdp); + if (brdp->iosize2 > 0) + release_region(brdp->ioaddr2, brdp->iosize2); +err_rel1: + release_region(brdp->ioaddr1, brdp->iosize1); +err: + return retval; } /*****************************************************************************/ @@ -2641,48 +2260,61 @@ static inline int stl_initech(stlbrd_t *brdp) * since the initial search and setup is very different. */ -static int __init stl_brdinit(stlbrd_t *brdp) +static int __devinit stl_brdinit(struct stlbrd *brdp) { - int i; + int i, retval; -#ifdef DEBUG - printk("stl_brdinit(brdp=%x)\n", (int) brdp); -#endif + pr_debug("stl_brdinit(brdp=%p)\n", brdp); switch (brdp->brdtype) { case BRD_EASYIO: case BRD_EASYIOPCI: - stl_initeio(brdp); + retval = stl_initeio(brdp); + if (retval) + goto err; break; case BRD_ECH: case BRD_ECHMC: case BRD_ECHPCI: case BRD_ECH64PCI: - stl_initech(brdp); + retval = stl_initech(brdp); + if (retval) + goto err; break; default: printk("STALLION: board=%d is unknown board type=%d\n", brdp->brdnr, brdp->brdtype); - return(ENODEV); + retval = -ENODEV; + goto err; } - stl_brds[brdp->brdnr] = brdp; if ((brdp->state & BRD_FOUND) == 0) { printk("STALLION: %s board not found, board=%d io=%x irq=%d\n", stl_brdnames[brdp->brdtype], brdp->brdnr, brdp->ioaddr1, brdp->irq); - return(ENODEV); + goto err_free; } - for (i = 0; (i < STL_MAXPANELS); i++) - if (brdp->panels[i] != (stlpanel_t *) NULL) + for (i = 0; i < STL_MAXPANELS; i++) + if (brdp->panels[i] != NULL) stl_initports(brdp, brdp->panels[i]); printk("STALLION: %s found, board=%d io=%x irq=%d " "nrpanels=%d nrports=%d\n", stl_brdnames[brdp->brdtype], brdp->brdnr, brdp->ioaddr1, brdp->irq, brdp->nrpanels, brdp->nrports); - return(0); + + return 0; +err_free: + free_irq(brdp->irq, brdp); + + stl_cleanup_panels(brdp); + + release_region(brdp->ioaddr1, brdp->iosize1); + if (brdp->iosize2 > 0) + release_region(brdp->ioaddr2, brdp->iosize2); +err: + return retval; } /*****************************************************************************/ @@ -2691,184 +2323,133 @@ static int __init stl_brdinit(stlbrd_t *brdp) * Find the next available board number that is free. */ -static inline int stl_getbrdnr(void) +static int __devinit stl_getbrdnr(void) { - int i; + unsigned int i; - for (i = 0; (i < STL_MAXBRDS); i++) { - if (stl_brds[i] == (stlbrd_t *) NULL) { + for (i = 0; i < STL_MAXBRDS; i++) + if (stl_brds[i] == NULL) { if (i >= stl_nrbrds) stl_nrbrds = i + 1; - return(i); + return i; } - } - return(-1); + + return -1; } /*****************************************************************************/ - -#ifdef CONFIG_PCI - /* * We have a Stallion board. Allocate a board structure and * initialize it. Read its IO and IRQ resources from PCI * configuration space. */ -static inline int stl_initpcibrd(int brdtype, struct pci_dev *devp) +static int __devinit stl_pciprobe(struct pci_dev *pdev, + const struct pci_device_id *ent) { - stlbrd_t *brdp; - -#ifdef DEBUG - printk("stl_initpcibrd(brdtype=%d,busnr=%x,devnr=%x)\n", brdtype, - devp->bus->number, devp->devfn); -#endif - - if (pci_enable_device(devp)) - return(-EIO); - if ((brdp = stl_allocbrd()) == (stlbrd_t *) NULL) - return(-ENOMEM); - if ((brdp->brdnr = stl_getbrdnr()) < 0) { - printk("STALLION: too many boards found, " + struct stlbrd *brdp; + unsigned int i, brdtype = ent->driver_data; + int brdnr, retval = -ENODEV; + + if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) + goto err; + + dev_info(&pdev->dev, "please, report this to LKML: %x/%x/%x\n", + pdev->vendor, pdev->device, pdev->class); + + retval = pci_enable_device(pdev); + if (retval) + goto err; + brdp = stl_allocbrd(); + if (brdp == NULL) { + retval = -ENOMEM; + goto err; + } + mutex_lock(&stl_brdslock); + brdnr = stl_getbrdnr(); + if (brdnr < 0) { + dev_err(&pdev->dev, "too many boards found, " "maximum supported %d\n", STL_MAXBRDS); - return(0); + mutex_unlock(&stl_brdslock); + goto err_fr; } - brdp->brdtype = brdtype; + brdp->brdnr = (unsigned int)brdnr; + stl_brds[brdp->brdnr] = brdp; + mutex_unlock(&stl_brdslock); -/* - * Different Stallion boards use the BAR registers in different ways, - * so set up io addresses based on board type. - */ -#ifdef DEBUG - printk("%s(%d): BAR[]=%x,%x,%x,%x IRQ=%x\n", __FILE__, __LINE__, - pci_resource_start(devp, 0), pci_resource_start(devp, 1), - pci_resource_start(devp, 2), pci_resource_start(devp, 3), devp->irq); -#endif + brdp->brdtype = brdtype; + brdp->state |= STL_PROBED; /* * We have all resources from the board, so let's setup the actual - * board structure now. - */ - switch (brdtype) { - case BRD_ECHPCI: - brdp->ioaddr2 = pci_resource_start(devp, 0); - brdp->ioaddr1 = pci_resource_start(devp, 1); - break; - case BRD_ECH64PCI: - brdp->ioaddr2 = pci_resource_start(devp, 2); - brdp->ioaddr1 = pci_resource_start(devp, 1); - break; - case BRD_EASYIOPCI: - brdp->ioaddr1 = pci_resource_start(devp, 2); - brdp->ioaddr2 = pci_resource_start(devp, 1); - break; - default: - printk("STALLION: unknown PCI board type=%d\n", brdtype); - break; - } - - brdp->irq = devp->irq; - stl_brdinit(brdp); - - return(0); -} - -/*****************************************************************************/ - -/* - * Find all Stallion PCI boards that might be installed. Initialize each - * one as it is found. - */ - - -static inline int stl_findpcibrds(void) -{ - struct pci_dev *dev = NULL; - int i, rc; - -#ifdef DEBUG - printk("stl_findpcibrds()\n"); -#endif - - for (i = 0; (i < stl_nrpcibrds); i++) - while ((dev = pci_find_device(stl_pcibrds[i].vendid, - stl_pcibrds[i].devid, dev))) { - -/* - * Found a device on the PCI bus that has our vendor and - * device ID. Need to check now that it is really us. + * board structure now. */ - if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE) - continue; - - rc = stl_initpcibrd(stl_pcibrds[i].brdtype, dev); - if (rc) - return(rc); - } + switch (brdtype) { + case BRD_ECHPCI: + brdp->ioaddr2 = pci_resource_start(pdev, 0); + brdp->ioaddr1 = pci_resource_start(pdev, 1); + break; + case BRD_ECH64PCI: + brdp->ioaddr2 = pci_resource_start(pdev, 2); + brdp->ioaddr1 = pci_resource_start(pdev, 1); + break; + case BRD_EASYIOPCI: + brdp->ioaddr1 = pci_resource_start(pdev, 2); + brdp->ioaddr2 = pci_resource_start(pdev, 1); + break; + default: + dev_err(&pdev->dev, "unknown PCI board type=%u\n", brdtype); + break; + } - return(0); -} + brdp->irq = pdev->irq; + retval = stl_brdinit(brdp); + if (retval) + goto err_null; -#endif + pci_set_drvdata(pdev, brdp); -/*****************************************************************************/ + for (i = 0; i < brdp->nrports; i++) + tty_register_device(stl_serial, + brdp->brdnr * STL_MAXPORTS + i, &pdev->dev); -/* - * Scan through all the boards in the configuration and see what we - * can find. Handle EIO and the ECH boards a little differently here - * since the initial search and setup is too different. - */ + return 0; +err_null: + stl_brds[brdp->brdnr] = NULL; +err_fr: + kfree(brdp); +err: + return retval; +} -static inline int stl_initbrds(void) +static void __devexit stl_pciremove(struct pci_dev *pdev) { - stlbrd_t *brdp; - stlconf_t *confp; - int i; + struct stlbrd *brdp = pci_get_drvdata(pdev); + unsigned int i; -#ifdef DEBUG - printk("stl_initbrds()\n"); -#endif + free_irq(brdp->irq, brdp); - if (stl_nrbrds > STL_MAXBRDS) { - printk("STALLION: too many boards in configuration table, " - "truncating to %d\n", STL_MAXBRDS); - stl_nrbrds = STL_MAXBRDS; - } + stl_cleanup_panels(brdp); -/* - * Firstly scan the list of static boards configured. Allocate - * resources and initialize the boards as found. - */ - for (i = 0; (i < stl_nrbrds); i++) { - confp = &stl_brdconf[i]; -#ifdef MODULE - stl_parsebrd(confp, stl_brdsp[i]); -#endif - if ((brdp = stl_allocbrd()) == (stlbrd_t *) NULL) - return(-ENOMEM); - brdp->brdnr = i; - brdp->brdtype = confp->brdtype; - brdp->ioaddr1 = confp->ioaddr1; - brdp->ioaddr2 = confp->ioaddr2; - brdp->irq = confp->irq; - brdp->irqtype = confp->irqtype; - stl_brdinit(brdp); - } + release_region(brdp->ioaddr1, brdp->iosize1); + if (brdp->iosize2 > 0) + release_region(brdp->ioaddr2, brdp->iosize2); -/* - * Find any dynamically supported boards. That is via module load - * line options or auto-detected on the PCI bus. - */ -#ifdef MODULE - stl_argbrds(); -#endif -#ifdef CONFIG_PCI - stl_findpcibrds(); -#endif + for (i = 0; i < brdp->nrports; i++) + tty_unregister_device(stl_serial, + brdp->brdnr * STL_MAXPORTS + i); - return(0); + stl_brds[brdp->brdnr] = NULL; + kfree(brdp); } +static struct pci_driver stl_pcidriver = { + .name = "stallion", + .id_table = stl_pcibrds, + .probe = stl_pciprobe, + .remove = __devexit_p(stl_pciremove) +}; + /*****************************************************************************/ /* @@ -2877,17 +2458,18 @@ static inline int stl_initbrds(void) static int stl_getbrdstats(combrd_t __user *bp) { - stlbrd_t *brdp; - stlpanel_t *panelp; - int i; + combrd_t stl_brdstats; + struct stlbrd *brdp; + struct stlpanel *panelp; + unsigned int i; if (copy_from_user(&stl_brdstats, bp, sizeof(combrd_t))) return -EFAULT; if (stl_brdstats.brd >= STL_MAXBRDS) - return(-ENODEV); + return -ENODEV; brdp = stl_brds[stl_brdstats.brd]; - if (brdp == (stlbrd_t *) NULL) - return(-ENODEV); + if (brdp == NULL) + return -ENODEV; memset(&stl_brdstats, 0, sizeof(combrd_t)); stl_brdstats.brd = brdp->brdnr; @@ -2899,7 +2481,7 @@ static int stl_getbrdstats(combrd_t __user *bp) stl_brdstats.irq = brdp->irq; stl_brdstats.nrpanels = brdp->nrpanels; stl_brdstats.nrports = brdp->nrports; - for (i = 0; (i < brdp->nrpanels); i++) { + for (i = 0; i < brdp->nrpanels; i++) { panelp = brdp->panels[i]; stl_brdstats.panels[i].panel = i; stl_brdstats.panels[i].hwid = panelp->hwid; @@ -2915,24 +2497,24 @@ static int stl_getbrdstats(combrd_t __user *bp) * Resolve the referenced port number into a port struct pointer. */ -static stlport_t *stl_getport(int brdnr, int panelnr, int portnr) +static struct stlport *stl_getport(int brdnr, int panelnr, int portnr) { - stlbrd_t *brdp; - stlpanel_t *panelp; + struct stlbrd *brdp; + struct stlpanel *panelp; - if ((brdnr < 0) || (brdnr >= STL_MAXBRDS)) - return((stlport_t *) NULL); + if (brdnr < 0 || brdnr >= STL_MAXBRDS) + return NULL; brdp = stl_brds[brdnr]; - if (brdp == (stlbrd_t *) NULL) - return((stlport_t *) NULL); - if ((panelnr < 0) || (panelnr >= brdp->nrpanels)) - return((stlport_t *) NULL); + if (brdp == NULL) + return NULL; + if (panelnr < 0 || (unsigned int)panelnr >= brdp->nrpanels) + return NULL; panelp = brdp->panels[panelnr]; - if (panelp == (stlpanel_t *) NULL) - return((stlport_t *) NULL); - if ((portnr < 0) || (portnr >= panelp->nrports)) - return((stlport_t *) NULL); - return(panelp->ports[portnr]); + if (panelp == NULL) + return NULL; + if (portnr < 0 || (unsigned int)portnr >= panelp->nrports) + return NULL; + return panelp->ports[portnr]; } /*****************************************************************************/ @@ -2943,8 +2525,9 @@ static stlport_t *stl_getport(int brdnr, int panelnr, int portnr) * what port to get stats for (used through board control device). */ -static int stl_getportstats(stlport_t *portp, comstats_t __user *cp) +static int stl_getportstats(struct stlport *portp, comstats_t __user *cp) { + comstats_t stl_comstats; unsigned char *head, *tail; unsigned long flags; @@ -2953,8 +2536,8 @@ static int stl_getportstats(stlport_t *portp, comstats_t __user *cp) return -EFAULT; portp = stl_getport(stl_comstats.brd, stl_comstats.panel, stl_comstats.port); - if (portp == (stlport_t *) NULL) - return(-ENODEV); + if (portp == NULL) + return -ENODEV; } portp->stats.state = portp->istate; @@ -2968,26 +2551,25 @@ static int stl_getportstats(stlport_t *portp, comstats_t __user *cp) portp->stats.lflags = 0; portp->stats.rxbuffered = 0; - save_flags(flags); - cli(); - if (portp->tty != (struct tty_struct *) NULL) { + spin_lock_irqsave(&stallion_lock, flags); + if (portp->tty != NULL) if (portp->tty->driver_data == portp) { portp->stats.ttystate = portp->tty->flags; - portp->stats.rxbuffered = portp->tty->flip.count; - if (portp->tty->termios != (struct termios *) NULL) { + /* No longer available as a statistic */ + portp->stats.rxbuffered = 1; /*portp->tty->flip.count; */ + if (portp->tty->termios != NULL) { portp->stats.cflags = portp->tty->termios->c_cflag; portp->stats.iflags = portp->tty->termios->c_iflag; portp->stats.oflags = portp->tty->termios->c_oflag; portp->stats.lflags = portp->tty->termios->c_lflag; } } - } - restore_flags(flags); + spin_unlock_irqrestore(&stallion_lock, flags); head = portp->tx.head; tail = portp->tx.tail; - portp->stats.txbuffered = ((head >= tail) ? (head - tail) : - (STL_TXBUFSIZE - (tail - head))); + portp->stats.txbuffered = (head >= tail) ? (head - tail) : + (STL_TXBUFSIZE - (tail - head)); portp->stats.signals = (unsigned long) stl_getsignals(portp); @@ -3001,15 +2583,17 @@ static int stl_getportstats(stlport_t *portp, comstats_t __user *cp) * Clear the port stats structure. We also return it zeroed out... */ -static int stl_clrportstats(stlport_t *portp, comstats_t __user *cp) +static int stl_clrportstats(struct stlport *portp, comstats_t __user *cp) { + comstats_t stl_comstats; + if (!portp) { if (copy_from_user(&stl_comstats, cp, sizeof(comstats_t))) return -EFAULT; portp = stl_getport(stl_comstats.brd, stl_comstats.panel, stl_comstats.port); - if (portp == (stlport_t *) NULL) - return(-ENODEV); + if (portp == NULL) + return -ENODEV; } memset(&portp->stats, 0, sizeof(comstats_t)); @@ -3026,17 +2610,18 @@ static int stl_clrportstats(stlport_t *portp, comstats_t __user *cp) * Return the entire driver ports structure to a user app. */ -static int stl_getportstruct(stlport_t __user *arg) +static int stl_getportstruct(struct stlport __user *arg) { - stlport_t *portp; + struct stlport stl_dummyport; + struct stlport *portp; - if (copy_from_user(&stl_dummyport, arg, sizeof(stlport_t))) + if (copy_from_user(&stl_dummyport, arg, sizeof(struct stlport))) return -EFAULT; portp = stl_getport(stl_dummyport.brdnr, stl_dummyport.panelnr, stl_dummyport.portnr); if (!portp) return -ENODEV; - return copy_to_user(arg, portp, sizeof(stlport_t)) ? -EFAULT : 0; + return copy_to_user(arg, portp, sizeof(struct stlport)) ? -EFAULT : 0; } /*****************************************************************************/ @@ -3045,18 +2630,19 @@ static int stl_getportstruct(stlport_t __user *arg) * Return the entire driver board structure to a user app. */ -static int stl_getbrdstruct(stlbrd_t __user *arg) +static int stl_getbrdstruct(struct stlbrd __user *arg) { - stlbrd_t *brdp; + struct stlbrd stl_dummybrd; + struct stlbrd *brdp; - if (copy_from_user(&stl_dummybrd, arg, sizeof(stlbrd_t))) + if (copy_from_user(&stl_dummybrd, arg, sizeof(struct stlbrd))) return -EFAULT; - if ((stl_dummybrd.brdnr < 0) || (stl_dummybrd.brdnr >= STL_MAXBRDS)) + if (stl_dummybrd.brdnr >= STL_MAXBRDS) return -ENODEV; brdp = stl_brds[stl_dummybrd.brdnr]; if (!brdp) - return(-ENODEV); - return copy_to_user(arg, brdp, sizeof(stlbrd_t)) ? -EFAULT : 0; + return -ENODEV; + return copy_to_user(arg, brdp, sizeof(struct stlbrd)) ? -EFAULT : 0; } /*****************************************************************************/ @@ -3072,14 +2658,11 @@ static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, uns int brdnr, rc; void __user *argp = (void __user *)arg; -#ifdef DEBUG - printk("stl_memioctl(ip=%x,fp=%x,cmd=%x,arg=%x)\n", (int) ip, - (int) fp, cmd, (int) arg); -#endif + pr_debug("stl_memioctl(ip=%p,fp=%p,cmd=%x,arg=%lx)\n", ip, fp, cmd,arg); brdnr = iminor(ip); if (brdnr >= STL_MAXBRDS) - return(-ENODEV); + return -ENODEV; rc = 0; switch (cmd) { @@ -3103,10 +2686,10 @@ static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, uns break; } - return(rc); + return rc; } -static struct tty_operations stl_ops = { +static const struct tty_operations stl_ops = { .open = stl_open, .close = stl_close, .write = stl_write, @@ -3130,64 +2713,6 @@ static struct tty_operations stl_ops = { .tiocmset = stl_tiocmset, }; -/*****************************************************************************/ - -int __init stl_init(void) -{ - int i; - printk(KERN_INFO "%s: version %s\n", stl_drvtitle, stl_drvversion); - - stl_initbrds(); - - stl_serial = alloc_tty_driver(STL_MAXBRDS * STL_MAXPORTS); - if (!stl_serial) - return -1; - -/* - * Allocate a temporary write buffer. - */ - stl_tmpwritebuf = (char *) stl_memalloc(STL_TXBUFSIZE); - if (stl_tmpwritebuf == (char *) NULL) - printk("STALLION: failed to allocate memory (size=%d)\n", - STL_TXBUFSIZE); - -/* - * Set up a character driver for per board stuff. This is mainly used - * to do stats ioctls on the ports. - */ - if (register_chrdev(STL_SIOMEMMAJOR, "staliomem", &stl_fsiomem)) - printk("STALLION: failed to register serial board device\n"); - devfs_mk_dir("staliomem"); - - stallion_class = class_simple_create(THIS_MODULE, "staliomem"); - for (i = 0; i < 4; i++) { - devfs_mk_cdev(MKDEV(STL_SIOMEMMAJOR, i), - S_IFCHR|S_IRUSR|S_IWUSR, - "staliomem/%d", i); - class_simple_device_add(stallion_class, MKDEV(STL_SIOMEMMAJOR, i), NULL, "staliomem%d", i); - } - - stl_serial->owner = THIS_MODULE; - stl_serial->driver_name = stl_drvname; - stl_serial->name = "ttyE"; - stl_serial->devfs_name = "tts/E"; - stl_serial->major = STL_SERIALMAJOR; - stl_serial->minor_start = 0; - stl_serial->type = TTY_DRIVER_TYPE_SERIAL; - stl_serial->subtype = SERIAL_TYPE_NORMAL; - stl_serial->init_termios = stl_deftermios; - stl_serial->flags = TTY_DRIVER_REAL_RAW; - tty_set_operations(stl_serial, &stl_ops); - - if (tty_register_driver(stl_serial)) { - put_tty_driver(stl_serial); - printk("STALLION: failed to register serial driver\n"); - return -1; - } - - return(0); -} - /*****************************************************************************/ /* CD1400 HARDWARE FUNCTIONS */ /*****************************************************************************/ @@ -3198,26 +2723,26 @@ int __init stl_init(void) * (Maybe should make this inline...) */ -static int stl_cd1400getreg(stlport_t *portp, int regnr) +static int stl_cd1400getreg(struct stlport *portp, int regnr) { outb((regnr + portp->uartaddr), portp->ioaddr); - return(inb(portp->ioaddr + EREG_DATA)); + return inb(portp->ioaddr + EREG_DATA); } -static void stl_cd1400setreg(stlport_t *portp, int regnr, int value) +static void stl_cd1400setreg(struct stlport *portp, int regnr, int value) { - outb((regnr + portp->uartaddr), portp->ioaddr); + outb(regnr + portp->uartaddr, portp->ioaddr); outb(value, portp->ioaddr + EREG_DATA); } -static int stl_cd1400updatereg(stlport_t *portp, int regnr, int value) +static int stl_cd1400updatereg(struct stlport *portp, int regnr, int value) { - outb((regnr + portp->uartaddr), portp->ioaddr); + outb(regnr + portp->uartaddr, portp->ioaddr); if (inb(portp->ioaddr + EREG_DATA) != value) { outb(value, portp->ioaddr + EREG_DATA); - return(1); + return 1; } - return(0); + return 0; } /*****************************************************************************/ @@ -3228,16 +2753,16 @@ static int stl_cd1400updatereg(stlport_t *portp, int regnr, int value) * identical when dealing with ports. */ -static int stl_cd1400panelinit(stlbrd_t *brdp, stlpanel_t *panelp) +static int stl_cd1400panelinit(struct stlbrd *brdp, struct stlpanel *panelp) { unsigned int gfrcr; int chipmask, i, j; int nrchips, uartaddr, ioaddr; + unsigned long flags; -#ifdef DEBUG - printk("stl_panelinit(brdp=%x,panelp=%x)\n", (int) brdp, (int) panelp); -#endif + pr_debug("stl_panelinit(brdp=%p,panelp=%p)\n", brdp, panelp); + spin_lock_irqsave(&brd_lock, flags); BRDENABLE(panelp->brdnr, panelp->pagenr); /* @@ -3245,13 +2770,12 @@ static int stl_cd1400panelinit(stlbrd_t *brdp, stlpanel_t *panelp) */ chipmask = 0; nrchips = panelp->nrports / CD1400_PORTS; - for (i = 0; (i < nrchips); i++) { + for (i = 0; i < nrchips; i++) { if (brdp->brdtype == BRD_ECHPCI) { outb((panelp->pagenr + (i >> 1)), brdp->ioctrl); ioaddr = panelp->iobase; - } else { + } else ioaddr = panelp->iobase + (EREG_BANKSIZE * (i >> 1)); - } uartaddr = (i & 0x01) ? 0x080 : 0; outb((GFRCR + uartaddr), ioaddr); outb(0, (ioaddr + EREG_DATA)); @@ -3259,10 +2783,10 @@ static int stl_cd1400panelinit(stlbrd_t *brdp, stlpanel_t *panelp) outb(CCR_RESETFULL, (ioaddr + EREG_DATA)); outb(CCR_RESETFULL, (ioaddr + EREG_DATA)); outb((GFRCR + uartaddr), ioaddr); - for (j = 0; (j < CCR_MAXWAIT); j++) { + for (j = 0; j < CCR_MAXWAIT; j++) if ((gfrcr = inb(ioaddr + EREG_DATA)) != 0) break; - } + if ((j >= CCR_MAXWAIT) || (gfrcr < 0x40) || (gfrcr > 0x60)) { printk("STALLION: cd1400 not responding, " "brd=%d panel=%d chip=%d\n", @@ -3275,7 +2799,8 @@ static int stl_cd1400panelinit(stlbrd_t *brdp, stlpanel_t *panelp) } BRDDISABLE(panelp->brdnr); - return(chipmask); + spin_unlock_irqrestore(&brd_lock, flags); + return chipmask; } /*****************************************************************************/ @@ -3284,17 +2809,17 @@ static int stl_cd1400panelinit(stlbrd_t *brdp, stlpanel_t *panelp) * Initialize hardware specific port registers. */ -static void stl_cd1400portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp) +static void stl_cd1400portinit(struct stlbrd *brdp, struct stlpanel *panelp, struct stlport *portp) { -#ifdef DEBUG - printk("stl_cd1400portinit(brdp=%x,panelp=%x,portp=%x)\n", - (int) brdp, (int) panelp, (int) portp); -#endif + unsigned long flags; + pr_debug("stl_cd1400portinit(brdp=%p,panelp=%p,portp=%p)\n", brdp, + panelp, portp); - if ((brdp == (stlbrd_t *) NULL) || (panelp == (stlpanel_t *) NULL) || - (portp == (stlport_t *) NULL)) + if ((brdp == NULL) || (panelp == NULL) || + (portp == NULL)) return; + spin_lock_irqsave(&brd_lock, flags); portp->ioaddr = panelp->iobase + (((brdp->brdtype == BRD_ECHPCI) || (portp->portnr < 8)) ? 0 : EREG_BANKSIZE); portp->uartaddr = (portp->portnr & 0x04) << 5; @@ -3305,6 +2830,7 @@ static void stl_cd1400portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *po stl_cd1400setreg(portp, LIVR, (portp->portnr << 3)); portp->hwid = stl_cd1400getreg(portp, GFRCR); BRDDISABLE(portp->brdnr); + spin_unlock_irqrestore(&brd_lock, flags); } /*****************************************************************************/ @@ -3314,15 +2840,13 @@ static void stl_cd1400portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *po * since it won't usually take too long to be ready. */ -static void stl_cd1400ccrwait(stlport_t *portp) +static void stl_cd1400ccrwait(struct stlport *portp) { int i; - for (i = 0; (i < CCR_MAXWAIT); i++) { - if (stl_cd1400getreg(portp, CCR) == 0) { + for (i = 0; i < CCR_MAXWAIT; i++) + if (stl_cd1400getreg(portp, CCR) == 0) return; - } - } printk("STALLION: cd1400 not responding, port=%d panel=%d brd=%d\n", portp->portnr, portp->panelnr, portp->brdnr); @@ -3335,9 +2859,9 @@ static void stl_cd1400ccrwait(stlport_t *portp) * settings. */ -static void stl_cd1400setport(stlport_t *portp, struct termios *tiosp) +static void stl_cd1400setport(struct stlport *portp, struct ktermios *tiosp) { - stlbrd_t *brdp; + struct stlbrd *brdp; unsigned long flags; unsigned int clkdiv, baudrate; unsigned char cor1, cor2, cor3; @@ -3361,7 +2885,7 @@ static void stl_cd1400setport(stlport_t *portp, struct termios *tiosp) sreroff = 0; brdp = stl_brds[portp->brdnr]; - if (brdp == (stlbrd_t *) NULL) + if (brdp == NULL) return; /* @@ -3458,8 +2982,8 @@ static void stl_cd1400setport(stlport_t *portp, struct termios *tiosp) baudrate = STL_CD1400MAXBAUD; if (baudrate > 0) { - for (clk = 0; (clk < CD1400_NUMCLKS); clk++) { - clkdiv = ((portp->clk / stl_cd1400clkdivs[clk]) / baudrate); + for (clk = 0; clk < CD1400_NUMCLKS; clk++) { + clkdiv = (portp->clk / stl_cd1400clkdivs[clk]) / baudrate; if (clkdiv < 0x100) break; } @@ -3474,9 +2998,8 @@ static void stl_cd1400setport(stlport_t *portp, struct termios *tiosp) mcor2 |= MCOR2_DCD; sreron |= SRER_MODEM; portp->flags |= ASYNC_CHECK_CD; - } else { + } else portp->flags &= ~ASYNC_CHECK_CD; - } /* * Setup cd1400 enhanced modes if we can. In particular we want to @@ -3501,21 +3024,18 @@ static void stl_cd1400setport(stlport_t *portp, struct termios *tiosp) * them all up. */ -#ifdef DEBUG - printk("SETPORT: portnr=%d panelnr=%d brdnr=%d\n", + pr_debug("SETPORT: portnr=%d panelnr=%d brdnr=%d\n", portp->portnr, portp->panelnr, portp->brdnr); - printk(" cor1=%x cor2=%x cor3=%x cor4=%x cor5=%x\n", + pr_debug(" cor1=%x cor2=%x cor3=%x cor4=%x cor5=%x\n", cor1, cor2, cor3, cor4, cor5); - printk(" mcor1=%x mcor2=%x rtpr=%x sreron=%x sreroff=%x\n", + pr_debug(" mcor1=%x mcor2=%x rtpr=%x sreron=%x sreroff=%x\n", mcor1, mcor2, rtpr, sreron, sreroff); - printk(" tcor=%x tbpr=%x rcor=%x rbpr=%x\n", clk, div, clk, div); - printk(" schr1=%x schr2=%x schr3=%x schr4=%x\n", + pr_debug(" tcor=%x tbpr=%x rcor=%x rbpr=%x\n", clk, div, clk, div); + pr_debug(" schr1=%x schr2=%x schr3=%x schr4=%x\n", tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP], tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP]); -#endif - save_flags(flags); - cli(); + spin_lock_irqsave(&brd_lock, flags); BRDENABLE(portp->brdnr, portp->pagenr); stl_cd1400setreg(portp, CAR, (portp->portnr & 0x3)); srer = stl_cd1400getreg(portp, SRER); @@ -3552,7 +3072,7 @@ static void stl_cd1400setport(stlport_t *portp, struct termios *tiosp) portp->sigs &= ~TIOCM_CD; stl_cd1400setreg(portp, SRER, ((srer & ~sreroff) | sreron)); BRDDISABLE(portp->brdnr); - restore_flags(flags); + spin_unlock_irqrestore(&brd_lock, flags); } /*****************************************************************************/ @@ -3561,15 +3081,13 @@ static void stl_cd1400setport(stlport_t *portp, struct termios *tiosp) * Set the state of the DTR and RTS signals. */ -static void stl_cd1400setsignals(stlport_t *portp, int dtr, int rts) +static void stl_cd1400setsignals(struct stlport *portp, int dtr, int rts) { unsigned char msvr1, msvr2; unsigned long flags; -#ifdef DEBUG - printk("stl_cd1400setsignals(portp=%x,dtr=%d,rts=%d)\n", - (int) portp, dtr, rts); -#endif + pr_debug("stl_cd1400setsignals(portp=%p,dtr=%d,rts=%d)\n", + portp, dtr, rts); msvr1 = 0; msvr2 = 0; @@ -3578,8 +3096,7 @@ static void stl_cd1400setsignals(stlport_t *portp, int dtr, int rts) if (rts > 0) msvr2 = MSVR2_RTS; - save_flags(flags); - cli(); + spin_lock_irqsave(&brd_lock, flags); BRDENABLE(portp->brdnr, portp->pagenr); stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); if (rts >= 0) @@ -3587,7 +3104,7 @@ static void stl_cd1400setsignals(stlport_t *portp, int dtr, int rts) if (dtr >= 0) stl_cd1400setreg(portp, MSVR1, msvr1); BRDDISABLE(portp->brdnr); - restore_flags(flags); + spin_unlock_irqrestore(&brd_lock, flags); } /*****************************************************************************/ @@ -3596,24 +3113,21 @@ static void stl_cd1400setsignals(stlport_t *portp, int dtr, int rts) * Return the state of the signals. */ -static int stl_cd1400getsignals(stlport_t *portp) +static int stl_cd1400getsignals(struct stlport *portp) { unsigned char msvr1, msvr2; unsigned long flags; int sigs; -#ifdef DEBUG - printk("stl_cd1400getsignals(portp=%x)\n", (int) portp); -#endif + pr_debug("stl_cd1400getsignals(portp=%p)\n", portp); - save_flags(flags); - cli(); + spin_lock_irqsave(&brd_lock, flags); BRDENABLE(portp->brdnr, portp->pagenr); stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); msvr1 = stl_cd1400getreg(portp, MSVR1); msvr2 = stl_cd1400getreg(portp, MSVR2); BRDDISABLE(portp->brdnr); - restore_flags(flags); + spin_unlock_irqrestore(&brd_lock, flags); sigs = 0; sigs |= (msvr1 & MSVR1_DCD) ? TIOCM_CD : 0; @@ -3626,7 +3140,7 @@ static int stl_cd1400getsignals(stlport_t *portp) #else sigs |= TIOCM_DSR; #endif - return(sigs); + return sigs; } /*****************************************************************************/ @@ -3635,15 +3149,13 @@ static int stl_cd1400getsignals(stlport_t *portp) * Enable/Disable the Transmitter and/or Receiver. */ -static void stl_cd1400enablerxtx(stlport_t *portp, int rx, int tx) +static void stl_cd1400enablerxtx(struct stlport *portp, int rx, int tx) { unsigned char ccr; unsigned long flags; -#ifdef DEBUG - printk("stl_cd1400enablerxtx(portp=%x,rx=%d,tx=%d)\n", - (int) portp, rx, tx); -#endif + pr_debug("stl_cd1400enablerxtx(portp=%p,rx=%d,tx=%d)\n", portp, rx, tx); + ccr = 0; if (tx == 0) @@ -3655,15 +3167,14 @@ static void stl_cd1400enablerxtx(stlport_t *portp, int rx, int tx) else if (rx > 0) ccr |= CCR_RXENABLE; - save_flags(flags); - cli(); + spin_lock_irqsave(&brd_lock, flags); BRDENABLE(portp->brdnr, portp->pagenr); stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); stl_cd1400ccrwait(portp); stl_cd1400setreg(portp, CCR, ccr); stl_cd1400ccrwait(portp); BRDDISABLE(portp->brdnr); - restore_flags(flags); + spin_unlock_irqrestore(&brd_lock, flags); } /*****************************************************************************/ @@ -3672,15 +3183,12 @@ static void stl_cd1400enablerxtx(stlport_t *portp, int rx, int tx) * Start/stop the Transmitter and/or Receiver. */ -static void stl_cd1400startrxtx(stlport_t *portp, int rx, int tx) +static void stl_cd1400startrxtx(struct stlport *portp, int rx, int tx) { unsigned char sreron, sreroff; unsigned long flags; -#ifdef DEBUG - printk("stl_cd1400startrxtx(portp=%x,rx=%d,tx=%d)\n", - (int) portp, rx, tx); -#endif + pr_debug("stl_cd1400startrxtx(portp=%p,rx=%d,tx=%d)\n", portp, rx, tx); sreron = 0; sreroff = 0; @@ -3695,8 +3203,7 @@ static void stl_cd1400startrxtx(stlport_t *portp, int rx, int tx) else if (rx > 0) sreron |= SRER_RXDATA; - save_flags(flags); - cli(); + spin_lock_irqsave(&brd_lock, flags); BRDENABLE(portp->brdnr, portp->pagenr); stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); stl_cd1400setreg(portp, SRER, @@ -3704,7 +3211,7 @@ static void stl_cd1400startrxtx(stlport_t *portp, int rx, int tx) BRDDISABLE(portp->brdnr); if (tx > 0) set_bit(ASYI_TXBUSY, &portp->istate); - restore_flags(flags); + spin_unlock_irqrestore(&brd_lock, flags); } /*****************************************************************************/ @@ -3713,34 +3220,29 @@ static void stl_cd1400startrxtx(stlport_t *portp, int rx, int tx) * Disable all interrupts from this port. */ -static void stl_cd1400disableintrs(stlport_t *portp) +static void stl_cd1400disableintrs(struct stlport *portp) { unsigned long flags; -#ifdef DEBUG - printk("stl_cd1400disableintrs(portp=%x)\n", (int) portp); -#endif - save_flags(flags); - cli(); + pr_debug("stl_cd1400disableintrs(portp=%p)\n", portp); + + spin_lock_irqsave(&brd_lock, flags); BRDENABLE(portp->brdnr, portp->pagenr); stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); stl_cd1400setreg(portp, SRER, 0); BRDDISABLE(portp->brdnr); - restore_flags(flags); + spin_unlock_irqrestore(&brd_lock, flags); } /*****************************************************************************/ -static void stl_cd1400sendbreak(stlport_t *portp, int len) +static void stl_cd1400sendbreak(struct stlport *portp, int len) { unsigned long flags; -#ifdef DEBUG - printk("stl_cd1400sendbreak(portp=%x,len=%d)\n", (int) portp, len); -#endif + pr_debug("stl_cd1400sendbreak(portp=%p,len=%d)\n", portp, len); - save_flags(flags); - cli(); + spin_lock_irqsave(&brd_lock, flags); BRDENABLE(portp->brdnr, portp->pagenr); stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); stl_cd1400setreg(portp, SRER, @@ -3750,7 +3252,7 @@ static void stl_cd1400sendbreak(stlport_t *portp, int len) portp->brklen = len; if (len == 1) portp->stats.txbreaks++; - restore_flags(flags); + spin_unlock_irqrestore(&brd_lock, flags); } /*****************************************************************************/ @@ -3759,23 +3261,20 @@ static void stl_cd1400sendbreak(stlport_t *portp, int len) * Take flow control actions... */ -static void stl_cd1400flowctrl(stlport_t *portp, int state) +static void stl_cd1400flowctrl(struct stlport *portp, int state) { struct tty_struct *tty; unsigned long flags; -#ifdef DEBUG - printk("stl_cd1400flowctrl(portp=%x,state=%x)\n", (int) portp, state); -#endif + pr_debug("stl_cd1400flowctrl(portp=%p,state=%x)\n", portp, state); - if (portp == (stlport_t *) NULL) + if (portp == NULL) return; tty = portp->tty; - if (tty == (struct tty_struct *) NULL) + if (tty == NULL) return; - save_flags(flags); - cli(); + spin_lock_irqsave(&brd_lock, flags); BRDENABLE(portp->brdnr, portp->pagenr); stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); @@ -3815,7 +3314,7 @@ static void stl_cd1400flowctrl(stlport_t *portp, int state) } BRDDISABLE(portp->brdnr); - restore_flags(flags); + spin_unlock_irqrestore(&brd_lock, flags); } /*****************************************************************************/ @@ -3824,23 +3323,20 @@ static void stl_cd1400flowctrl(stlport_t *portp, int state) * Send a flow control character... */ -static void stl_cd1400sendflow(stlport_t *portp, int state) +static void stl_cd1400sendflow(struct stlport *portp, int state) { struct tty_struct *tty; unsigned long flags; -#ifdef DEBUG - printk("stl_cd1400sendflow(portp=%x,state=%x)\n", (int) portp, state); -#endif + pr_debug("stl_cd1400sendflow(portp=%p,state=%x)\n", portp, state); - if (portp == (stlport_t *) NULL) + if (portp == NULL) return; tty = portp->tty; - if (tty == (struct tty_struct *) NULL) + if (tty == NULL) return; - save_flags(flags); - cli(); + spin_lock_irqsave(&brd_lock, flags); BRDENABLE(portp->brdnr, portp->pagenr); stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); if (state) { @@ -3855,24 +3351,21 @@ static void stl_cd1400sendflow(stlport_t *portp, int state) stl_cd1400ccrwait(portp); } BRDDISABLE(portp->brdnr); - restore_flags(flags); + spin_unlock_irqrestore(&brd_lock, flags); } /*****************************************************************************/ -static void stl_cd1400flush(stlport_t *portp) +static void stl_cd1400flush(struct stlport *portp) { unsigned long flags; -#ifdef DEBUG - printk("stl_cd1400flush(portp=%x)\n", (int) portp); -#endif + pr_debug("stl_cd1400flush(portp=%p)\n", portp); - if (portp == (stlport_t *) NULL) + if (portp == NULL) return; - save_flags(flags); - cli(); + spin_lock_irqsave(&brd_lock, flags); BRDENABLE(portp->brdnr, portp->pagenr); stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); stl_cd1400ccrwait(portp); @@ -3880,7 +3373,7 @@ static void stl_cd1400flush(stlport_t *portp) stl_cd1400ccrwait(portp); portp->tx.tail = portp->tx.head; BRDDISABLE(portp->brdnr); - restore_flags(flags); + spin_unlock_irqrestore(&brd_lock, flags); } /*****************************************************************************/ @@ -3892,16 +3385,14 @@ static void stl_cd1400flush(stlport_t *portp) * maintains the busy port flag. */ -static int stl_cd1400datastate(stlport_t *portp) +static int stl_cd1400datastate(struct stlport *portp) { -#ifdef DEBUG - printk("stl_cd1400datastate(portp=%x)\n", (int) portp); -#endif + pr_debug("stl_cd1400datastate(portp=%p)\n", portp); - if (portp == (stlport_t *) NULL) - return(0); + if (portp == NULL) + return 0; - return(test_bit(ASYI_TXBUSY, &portp->istate) ? 1 : 0); + return test_bit(ASYI_TXBUSY, &portp->istate) ? 1 : 0; } /*****************************************************************************/ @@ -3910,15 +3401,13 @@ static int stl_cd1400datastate(stlport_t *portp) * Interrupt service routine for cd1400 EasyIO boards. */ -static void stl_cd1400eiointr(stlpanel_t *panelp, unsigned int iobase) +static void stl_cd1400eiointr(struct stlpanel *panelp, unsigned int iobase) { unsigned char svrtype; -#ifdef DEBUG - printk("stl_cd1400eiointr(panelp=%x,iobase=%x)\n", - (int) panelp, iobase); -#endif + pr_debug("stl_cd1400eiointr(panelp=%p,iobase=%x)\n", panelp, iobase); + spin_lock(&brd_lock); outb(SVRR, iobase); svrtype = inb(iobase + EREG_DATA); if (panelp->nrports > 4) { @@ -3932,6 +3421,8 @@ static void stl_cd1400eiointr(stlpanel_t *panelp, unsigned int iobase) stl_cd1400txisr(panelp, iobase); else if (svrtype & SVRR_MDM) stl_cd1400mdmisr(panelp, iobase); + + spin_unlock(&brd_lock); } /*****************************************************************************/ @@ -3940,14 +3431,11 @@ static void stl_cd1400eiointr(stlpanel_t *panelp, unsigned int iobase) * Interrupt service routine for cd1400 panels. */ -static void stl_cd1400echintr(stlpanel_t *panelp, unsigned int iobase) +static void stl_cd1400echintr(struct stlpanel *panelp, unsigned int iobase) { unsigned char svrtype; -#ifdef DEBUG - printk("stl_cd1400echintr(panelp=%x,iobase=%x)\n", (int) panelp, - iobase); -#endif + pr_debug("stl_cd1400echintr(panelp=%p,iobase=%x)\n", panelp, iobase); outb(SVRR, iobase); svrtype = inb(iobase + EREG_DATA); @@ -3969,7 +3457,7 @@ static void stl_cd1400echintr(stlpanel_t *panelp, unsigned int iobase) * this is the only way to generate them on the cd1400. */ -static inline int stl_cd1400breakisr(stlport_t *portp, int ioaddr) +static int stl_cd1400breakisr(struct stlport *portp, int ioaddr) { if (portp->brklen == 1) { outb((COR2 + portp->uartaddr), ioaddr); @@ -3981,20 +3469,20 @@ static inline int stl_cd1400breakisr(stlport_t *portp, int ioaddr) outb((SRER + portp->uartaddr), ioaddr); outb((inb(ioaddr + EREG_DATA) & ~(SRER_TXDATA | SRER_TXEMPTY)), (ioaddr + EREG_DATA)); - return(1); + return 1; } else if (portp->brklen > 1) { outb((TDR + portp->uartaddr), ioaddr); outb(ETC_CMD, (ioaddr + EREG_DATA)); outb(ETC_STOPBREAK, (ioaddr + EREG_DATA)); portp->brklen = -1; - return(1); + return 1; } else { outb((COR2 + portp->uartaddr), ioaddr); outb((inb(ioaddr + EREG_DATA) & ~COR2_ETC), (ioaddr + EREG_DATA)); portp->brklen = 0; } - return(0); + return 0; } /*****************************************************************************/ @@ -4011,16 +3499,14 @@ static inline int stl_cd1400breakisr(stlport_t *portp, int ioaddr) * be NULL if the buffer has been freed. */ -static void stl_cd1400txisr(stlpanel_t *panelp, int ioaddr) +static void stl_cd1400txisr(struct stlpanel *panelp, int ioaddr) { - stlport_t *portp; + struct stlport *portp; int len, stlen; char *head, *tail; unsigned char ioack, srer; -#ifdef DEBUG - printk("stl_cd1400txisr(panelp=%x,ioaddr=%x)\n", (int) panelp, ioaddr); -#endif + pr_debug("stl_cd1400txisr(panelp=%p,ioaddr=%x)\n", panelp, ioaddr); ioack = inb(ioaddr + EREG_TXACK); if (((ioack & panelp->ackmask) != 0) || @@ -4059,9 +3545,9 @@ static void stl_cd1400txisr(stlpanel_t *panelp, int ioaddr) } outb(srer, (ioaddr + EREG_DATA)); } else { - len = MIN(len, CD1400_TXFIFOSIZE); + len = min(len, CD1400_TXFIFOSIZE); portp->stats.txtotal += len; - stlen = MIN(len, ((portp->tx.buf + STL_TXBUFSIZE) - tail)); + stlen = min(len, ((portp->tx.buf + STL_TXBUFSIZE) - tail)); outb((TDR + portp->uartaddr), ioaddr); outsb((ioaddr + EREG_DATA), tail, stlen); len -= stlen; @@ -4092,17 +3578,15 @@ stl_txalldone: * shutdown a port not in user context. Need to handle this case. */ -static void stl_cd1400rxisr(stlpanel_t *panelp, int ioaddr) +static void stl_cd1400rxisr(struct stlpanel *panelp, int ioaddr) { - stlport_t *portp; + struct stlport *portp; struct tty_struct *tty; unsigned int ioack, len, buflen; unsigned char status; char ch; -#ifdef DEBUG - printk("stl_cd1400rxisr(panelp=%x,ioaddr=%x)\n", (int) panelp, ioaddr); -#endif + pr_debug("stl_cd1400rxisr(panelp=%p,ioaddr=%x)\n", panelp, ioaddr); ioack = inb(ioaddr + EREG_RXACK); if ((ioack & panelp->ackmask) != 0) { @@ -4115,23 +3599,19 @@ static void stl_cd1400rxisr(stlpanel_t *panelp, int ioaddr) if ((ioack & ACK_TYPMASK) == ACK_TYPRXGOOD) { outb((RDCR + portp->uartaddr), ioaddr); len = inb(ioaddr + EREG_DATA); - if ((tty == (struct tty_struct *) NULL) || - (tty->flip.char_buf_ptr == (char *) NULL) || - ((buflen = TTY_FLIPBUF_SIZE - tty->flip.count) == 0)) { - len = MIN(len, sizeof(stl_unwanted)); + if (tty == NULL || (buflen = tty_buffer_request_room(tty, len)) == 0) { + len = min(len, sizeof(stl_unwanted)); outb((RDSR + portp->uartaddr), ioaddr); insb((ioaddr + EREG_DATA), &stl_unwanted[0], len); portp->stats.rxlost += len; portp->stats.rxtotal += len; } else { - len = MIN(len, buflen); + len = min(len, buflen); if (len > 0) { + unsigned char *ptr; outb((RDSR + portp->uartaddr), ioaddr); - insb((ioaddr + EREG_DATA), tty->flip.char_buf_ptr, len); - memset(tty->flip.flag_buf_ptr, 0, len); - tty->flip.flag_buf_ptr += len; - tty->flip.char_buf_ptr += len; - tty->flip.count += len; + tty_prepare_flip_string(tty, &ptr, len); + insb((ioaddr + EREG_DATA), ptr, len); tty_schedule_flip(tty); portp->stats.rxtotal += len; } @@ -4155,8 +3635,7 @@ static void stl_cd1400rxisr(stlpanel_t *panelp, int ioaddr) portp->stats.txxoff++; goto stl_rxalldone; } - if ((tty != (struct tty_struct *) NULL) && - ((portp->rxignoremsk & status) == 0)) { + if (tty != NULL && (portp->rxignoremsk & status) == 0) { if (portp->rxmarkmsk & status) { if (status & ST_BREAK) { status = TTY_BREAK; @@ -4164,26 +3643,18 @@ static void stl_cd1400rxisr(stlpanel_t *panelp, int ioaddr) do_SAK(tty); BRDENABLE(portp->brdnr, portp->pagenr); } - } else if (status & ST_PARITY) { + } else if (status & ST_PARITY) status = TTY_PARITY; - } else if (status & ST_FRAMING) { + else if (status & ST_FRAMING) status = TTY_FRAME; - } else if(status & ST_OVERRUN) { + else if(status & ST_OVERRUN) status = TTY_OVERRUN; - } else { + else status = 0; - } - } else { + } else status = 0; - } - if (tty->flip.char_buf_ptr != (char *) NULL) { - if (tty->flip.count < TTY_FLIPBUF_SIZE) { - *tty->flip.flag_buf_ptr++ = status; - *tty->flip.char_buf_ptr++ = ch; - tty->flip.count++; - } - tty_schedule_flip(tty); - } + tty_insert_flip_char(tty, ch, status); + tty_schedule_flip(tty); } } else { printk("STALLION: bad RX interrupt ack value=%x\n", ioack); @@ -4203,15 +3674,13 @@ stl_rxalldone: * processing routine. */ -static void stl_cd1400mdmisr(stlpanel_t *panelp, int ioaddr) +static void stl_cd1400mdmisr(struct stlpanel *panelp, int ioaddr) { - stlport_t *portp; + struct stlport *portp; unsigned int ioack; unsigned char misr; -#ifdef DEBUG - printk("stl_cd1400mdmisr(panelp=%x)\n", (int) panelp); -#endif + pr_debug("stl_cd1400mdmisr(panelp=%p)\n", panelp); ioack = inb(ioaddr + EREG_MDACK); if (((ioack & panelp->ackmask) != 0) || @@ -4243,26 +3712,26 @@ static void stl_cd1400mdmisr(stlpanel_t *panelp, int ioaddr) * (Maybe should make this inline...) */ -static int stl_sc26198getreg(stlport_t *portp, int regnr) +static int stl_sc26198getreg(struct stlport *portp, int regnr) { outb((regnr | portp->uartaddr), (portp->ioaddr + XP_ADDR)); - return(inb(portp->ioaddr + XP_DATA)); + return inb(portp->ioaddr + XP_DATA); } -static void stl_sc26198setreg(stlport_t *portp, int regnr, int value) +static void stl_sc26198setreg(struct stlport *portp, int regnr, int value) { outb((regnr | portp->uartaddr), (portp->ioaddr + XP_ADDR)); outb(value, (portp->ioaddr + XP_DATA)); } -static int stl_sc26198updatereg(stlport_t *portp, int regnr, int value) +static int stl_sc26198updatereg(struct stlport *portp, int regnr, int value) { outb((regnr | portp->uartaddr), (portp->ioaddr + XP_ADDR)); if (inb(portp->ioaddr + XP_DATA) != value) { outb(value, (portp->ioaddr + XP_DATA)); - return(1); + return 1; } - return(0); + return 0; } /*****************************************************************************/ @@ -4271,14 +3740,14 @@ static int stl_sc26198updatereg(stlport_t *portp, int regnr, int value) * Functions to get and set the sc26198 global registers. */ -static int stl_sc26198getglobreg(stlport_t *portp, int regnr) +static int stl_sc26198getglobreg(struct stlport *portp, int regnr) { outb(regnr, (portp->ioaddr + XP_ADDR)); - return(inb(portp->ioaddr + XP_DATA)); + return inb(portp->ioaddr + XP_DATA); } #if 0 -static void stl_sc26198setglobreg(stlport_t *portp, int regnr, int value) +static void stl_sc26198setglobreg(struct stlport *portp, int regnr, int value) { outb(regnr, (portp->ioaddr + XP_ADDR)); outb(value, (portp->ioaddr + XP_DATA)); @@ -4293,15 +3762,12 @@ static void stl_sc26198setglobreg(stlport_t *portp, int regnr, int value) * identical when dealing with ports. */ -static int stl_sc26198panelinit(stlbrd_t *brdp, stlpanel_t *panelp) +static int stl_sc26198panelinit(struct stlbrd *brdp, struct stlpanel *panelp) { int chipmask, i; int nrchips, ioaddr; -#ifdef DEBUG - printk("stl_sc26198panelinit(brdp=%x,panelp=%x)\n", - (int) brdp, (int) panelp); -#endif + pr_debug("stl_sc26198panelinit(brdp=%p,panelp=%p)\n", brdp, panelp); BRDENABLE(panelp->brdnr, panelp->pagenr); @@ -4313,7 +3779,7 @@ static int stl_sc26198panelinit(stlbrd_t *brdp, stlpanel_t *panelp) if (brdp->brdtype == BRD_ECHPCI) outb(panelp->pagenr, brdp->ioctrl); - for (i = 0; (i < nrchips); i++) { + for (i = 0; i < nrchips; i++) { ioaddr = panelp->iobase + (i * 4); outb(SCCR, (ioaddr + XP_ADDR)); outb(CR_RESETALL, (ioaddr + XP_DATA)); @@ -4332,7 +3798,7 @@ static int stl_sc26198panelinit(stlbrd_t *brdp, stlpanel_t *panelp) } BRDDISABLE(panelp->brdnr); - return(chipmask); + return chipmask; } /*****************************************************************************/ @@ -4341,15 +3807,13 @@ static int stl_sc26198panelinit(stlbrd_t *brdp, stlpanel_t *panelp) * Initialize hardware specific port registers. */ -static void stl_sc26198portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp) +static void stl_sc26198portinit(struct stlbrd *brdp, struct stlpanel *panelp, struct stlport *portp) { -#ifdef DEBUG - printk("stl_sc26198portinit(brdp=%x,panelp=%x,portp=%x)\n", - (int) brdp, (int) panelp, (int) portp); -#endif + pr_debug("stl_sc26198portinit(brdp=%p,panelp=%p,portp=%p)\n", brdp, + panelp, portp); - if ((brdp == (stlbrd_t *) NULL) || (panelp == (stlpanel_t *) NULL) || - (portp == (stlport_t *) NULL)) + if ((brdp == NULL) || (panelp == NULL) || + (portp == NULL)) return; portp->ioaddr = panelp->iobase + ((portp->portnr < 8) ? 0 : 4); @@ -4369,9 +3833,9 @@ static void stl_sc26198portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *p * settings. */ -static void stl_sc26198setport(stlport_t *portp, struct termios *tiosp) +static void stl_sc26198setport(struct stlport *portp, struct ktermios *tiosp) { - stlbrd_t *brdp; + struct stlbrd *brdp; unsigned long flags; unsigned int baudrate; unsigned char mr0, mr1, mr2, clk; @@ -4386,7 +3850,7 @@ static void stl_sc26198setport(stlport_t *portp, struct termios *tiosp) imroff = 0; brdp = stl_brds[portp->brdnr]; - if (brdp == (stlbrd_t *) NULL) + if (brdp == NULL) return; /* @@ -4435,9 +3899,8 @@ static void stl_sc26198setport(stlport_t *portp, struct termios *tiosp) mr1 |= (MR1_PARENB | MR1_PARODD); else mr1 |= (MR1_PARENB | MR1_PAREVEN); - } else { + } else mr1 |= MR1_PARNONE; - } mr1 |= MR1_ERRBLOCK; @@ -4477,12 +3940,10 @@ static void stl_sc26198setport(stlport_t *portp, struct termios *tiosp) if (baudrate > STL_SC26198MAXBAUD) baudrate = STL_SC26198MAXBAUD; - if (baudrate > 0) { - for (clk = 0; (clk < SC26198_NRBAUDS); clk++) { + if (baudrate > 0) + for (clk = 0; clk < SC26198_NRBAUDS; clk++) if (baudrate <= sc26198_baudtable[clk]) break; - } - } /* * Check what form of modem signaling is required and set it up. @@ -4504,9 +3965,9 @@ static void stl_sc26198setport(stlport_t *portp, struct termios *tiosp) if (tiosp->c_iflag & IXON) { mr0 |= MR0_SWFTX | MR0_SWFT; imron |= IR_XONXOFF; - } else { + } else imroff |= IR_XONXOFF; - } + if (tiosp->c_iflag & IXOFF) mr0 |= MR0_SWFRX; @@ -4520,18 +3981,15 @@ static void stl_sc26198setport(stlport_t *portp, struct termios *tiosp) * them all up. */ -#ifdef DEBUG - printk("SETPORT: portnr=%d panelnr=%d brdnr=%d\n", + pr_debug("SETPORT: portnr=%d panelnr=%d brdnr=%d\n", portp->portnr, portp->panelnr, portp->brdnr); - printk(" mr0=%x mr1=%x mr2=%x clk=%x\n", mr0, mr1, mr2, clk); - printk(" iopr=%x imron=%x imroff=%x\n", iopr, imron, imroff); - printk(" schr1=%x schr2=%x schr3=%x schr4=%x\n", + pr_debug(" mr0=%x mr1=%x mr2=%x clk=%x\n", mr0, mr1, mr2, clk); + pr_debug(" iopr=%x imron=%x imroff=%x\n", iopr, imron, imroff); + pr_debug(" schr1=%x schr2=%x schr3=%x schr4=%x\n", tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP], tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP]); -#endif - save_flags(flags); - cli(); + spin_lock_irqsave(&brd_lock, flags); BRDENABLE(portp->brdnr, portp->pagenr); stl_sc26198setreg(portp, IMR, 0); stl_sc26198updatereg(portp, MR0, mr0); @@ -4558,7 +4016,7 @@ static void stl_sc26198setport(stlport_t *portp, struct termios *tiosp) portp->imr = (portp->imr & ~imroff) | imron; stl_sc26198setreg(portp, IMR, portp->imr); BRDDISABLE(portp->brdnr); - restore_flags(flags); + spin_unlock_irqrestore(&brd_lock, flags); } /*****************************************************************************/ @@ -4567,15 +4025,13 @@ static void stl_sc26198setport(stlport_t *portp, struct termios *tiosp) * Set the state of the DTR and RTS signals. */ -static void stl_sc26198setsignals(stlport_t *portp, int dtr, int rts) +static void stl_sc26198setsignals(struct stlport *portp, int dtr, int rts) { unsigned char iopioron, iopioroff; unsigned long flags; -#ifdef DEBUG - printk("stl_sc26198setsignals(portp=%x,dtr=%d,rts=%d)\n", - (int) portp, dtr, rts); -#endif + pr_debug("stl_sc26198setsignals(portp=%p,dtr=%d,rts=%d)\n", portp, + dtr, rts); iopioron = 0; iopioroff = 0; @@ -4588,13 +4044,12 @@ static void stl_sc26198setsignals(stlport_t *portp, int dtr, int rts) else if (rts > 0) iopioron |= IPR_RTS; - save_flags(flags); - cli(); + spin_lock_irqsave(&brd_lock, flags); BRDENABLE(portp->brdnr, portp->pagenr); stl_sc26198setreg(portp, IOPIOR, ((stl_sc26198getreg(portp, IOPIOR) & ~iopioroff) | iopioron)); BRDDISABLE(portp->brdnr); - restore_flags(flags); + spin_unlock_irqrestore(&brd_lock, flags); } /*****************************************************************************/ @@ -4603,22 +4058,19 @@ static void stl_sc26198setsignals(stlport_t *portp, int dtr, int rts) * Return the state of the signals. */ -static int stl_sc26198getsignals(stlport_t *portp) +static int stl_sc26198getsignals(struct stlport *portp) { unsigned char ipr; unsigned long flags; int sigs; -#ifdef DEBUG - printk("stl_sc26198getsignals(portp=%x)\n", (int) portp); -#endif + pr_debug("stl_sc26198getsignals(portp=%p)\n", portp); - save_flags(flags); - cli(); + spin_lock_irqsave(&brd_lock, flags); BRDENABLE(portp->brdnr, portp->pagenr); ipr = stl_sc26198getreg(portp, IPR); BRDDISABLE(portp->brdnr); - restore_flags(flags); + spin_unlock_irqrestore(&brd_lock, flags); sigs = 0; sigs |= (ipr & IPR_DCD) ? 0 : TIOCM_CD; @@ -4626,7 +4078,7 @@ static int stl_sc26198getsignals(stlport_t *portp) sigs |= (ipr & IPR_DTR) ? 0: TIOCM_DTR; sigs |= (ipr & IPR_RTS) ? 0: TIOCM_RTS; sigs |= TIOCM_DSR; - return(sigs); + return sigs; } /*****************************************************************************/ @@ -4635,15 +4087,12 @@ static int stl_sc26198getsignals(stlport_t *portp) * Enable/Disable the Transmitter and/or Receiver. */ -static void stl_sc26198enablerxtx(stlport_t *portp, int rx, int tx) +static void stl_sc26198enablerxtx(struct stlport *portp, int rx, int tx) { unsigned char ccr; unsigned long flags; -#ifdef DEBUG - printk("stl_sc26198enablerxtx(portp=%x,rx=%d,tx=%d)\n", - (int) portp, rx, tx); -#endif + pr_debug("stl_sc26198enablerxtx(portp=%p,rx=%d,tx=%d)\n", portp, rx,tx); ccr = portp->crenable; if (tx == 0) @@ -4655,13 +4104,12 @@ static void stl_sc26198enablerxtx(stlport_t *portp, int rx, int tx) else if (rx > 0) ccr |= CR_RXENABLE; - save_flags(flags); - cli(); + spin_lock_irqsave(&brd_lock, flags); BRDENABLE(portp->brdnr, portp->pagenr); stl_sc26198setreg(portp, SCCR, ccr); BRDDISABLE(portp->brdnr); portp->crenable = ccr; - restore_flags(flags); + spin_unlock_irqrestore(&brd_lock, flags); } /*****************************************************************************/ @@ -4670,15 +4118,12 @@ static void stl_sc26198enablerxtx(stlport_t *portp, int rx, int tx) * Start/stop the Transmitter and/or Receiver. */ -static void stl_sc26198startrxtx(stlport_t *portp, int rx, int tx) +static void stl_sc26198startrxtx(struct stlport *portp, int rx, int tx) { unsigned char imr; unsigned long flags; -#ifdef DEBUG - printk("stl_sc26198startrxtx(portp=%x,rx=%d,tx=%d)\n", - (int) portp, rx, tx); -#endif + pr_debug("stl_sc26198startrxtx(portp=%p,rx=%d,tx=%d)\n", portp, rx, tx); imr = portp->imr; if (tx == 0) @@ -4690,15 +4135,14 @@ static void stl_sc26198startrxtx(stlport_t *portp, int rx, int tx) else if (rx > 0) imr |= IR_RXRDY | IR_RXBREAK | IR_RXWATCHDOG; - save_flags(flags); - cli(); + spin_lock_irqsave(&brd_lock, flags); BRDENABLE(portp->brdnr, portp->pagenr); stl_sc26198setreg(portp, IMR, imr); BRDDISABLE(portp->brdnr); portp->imr = imr; if (tx > 0) set_bit(ASYI_TXBUSY, &portp->istate); - restore_flags(flags); + spin_unlock_irqrestore(&brd_lock, flags); } /*****************************************************************************/ @@ -4707,44 +4151,38 @@ static void stl_sc26198startrxtx(stlport_t *portp, int rx, int tx) * Disable all interrupts from this port. */ -static void stl_sc26198disableintrs(stlport_t *portp) +static void stl_sc26198disableintrs(struct stlport *portp) { unsigned long flags; -#ifdef DEBUG - printk("stl_sc26198disableintrs(portp=%x)\n", (int) portp); -#endif + pr_debug("stl_sc26198disableintrs(portp=%p)\n", portp); - save_flags(flags); - cli(); + spin_lock_irqsave(&brd_lock, flags); BRDENABLE(portp->brdnr, portp->pagenr); portp->imr = 0; stl_sc26198setreg(portp, IMR, 0); BRDDISABLE(portp->brdnr); - restore_flags(flags); + spin_unlock_irqrestore(&brd_lock, flags); } /*****************************************************************************/ -static void stl_sc26198sendbreak(stlport_t *portp, int len) +static void stl_sc26198sendbreak(struct stlport *portp, int len) { unsigned long flags; -#ifdef DEBUG - printk("stl_sc26198sendbreak(portp=%x,len=%d)\n", (int) portp, len); -#endif + pr_debug("stl_sc26198sendbreak(portp=%p,len=%d)\n", portp, len); - save_flags(flags); - cli(); + spin_lock_irqsave(&brd_lock, flags); BRDENABLE(portp->brdnr, portp->pagenr); if (len == 1) { stl_sc26198setreg(portp, SCCR, CR_TXSTARTBREAK); portp->stats.txbreaks++; - } else { + } else stl_sc26198setreg(portp, SCCR, CR_TXSTOPBREAK); - } + BRDDISABLE(portp->brdnr); - restore_flags(flags); + spin_unlock_irqrestore(&brd_lock, flags); } /*****************************************************************************/ @@ -4753,24 +4191,21 @@ static void stl_sc26198sendbreak(stlport_t *portp, int len) * Take flow control actions... */ -static void stl_sc26198flowctrl(stlport_t *portp, int state) +static void stl_sc26198flowctrl(struct stlport *portp, int state) { struct tty_struct *tty; unsigned long flags; unsigned char mr0; -#ifdef DEBUG - printk("stl_sc26198flowctrl(portp=%x,state=%x)\n", (int) portp, state); -#endif + pr_debug("stl_sc26198flowctrl(portp=%p,state=%x)\n", portp, state); - if (portp == (stlport_t *) NULL) + if (portp == NULL) return; tty = portp->tty; - if (tty == (struct tty_struct *) NULL) + if (tty == NULL) return; - save_flags(flags); - cli(); + spin_lock_irqsave(&brd_lock, flags); BRDENABLE(portp->brdnr, portp->pagenr); if (state) { @@ -4816,7 +4251,7 @@ static void stl_sc26198flowctrl(stlport_t *portp, int state) } BRDDISABLE(portp->brdnr); - restore_flags(flags); + spin_unlock_irqrestore(&brd_lock, flags); } /*****************************************************************************/ @@ -4825,24 +4260,21 @@ static void stl_sc26198flowctrl(stlport_t *portp, int state) * Send a flow control character. */ -static void stl_sc26198sendflow(stlport_t *portp, int state) +static void stl_sc26198sendflow(struct stlport *portp, int state) { struct tty_struct *tty; unsigned long flags; unsigned char mr0; -#ifdef DEBUG - printk("stl_sc26198sendflow(portp=%x,state=%x)\n", (int) portp, state); -#endif + pr_debug("stl_sc26198sendflow(portp=%p,state=%x)\n", portp, state); - if (portp == (stlport_t *) NULL) + if (portp == NULL) return; tty = portp->tty; - if (tty == (struct tty_struct *) NULL) + if (tty == NULL) return; - save_flags(flags); - cli(); + spin_lock_irqsave(&brd_lock, flags); BRDENABLE(portp->brdnr, portp->pagenr); if (state) { mr0 = stl_sc26198getreg(portp, MR0); @@ -4862,30 +4294,27 @@ static void stl_sc26198sendflow(stlport_t *portp, int state) stl_sc26198setreg(portp, MR0, mr0); } BRDDISABLE(portp->brdnr); - restore_flags(flags); + spin_unlock_irqrestore(&brd_lock, flags); } /*****************************************************************************/ -static void stl_sc26198flush(stlport_t *portp) +static void stl_sc26198flush(struct stlport *portp) { unsigned long flags; -#ifdef DEBUG - printk("stl_sc26198flush(portp=%x)\n", (int) portp); -#endif + pr_debug("stl_sc26198flush(portp=%p)\n", portp); - if (portp == (stlport_t *) NULL) + if (portp == NULL) return; - save_flags(flags); - cli(); + spin_lock_irqsave(&brd_lock, flags); BRDENABLE(portp->brdnr, portp->pagenr); stl_sc26198setreg(portp, SCCR, CR_TXRESET); stl_sc26198setreg(portp, SCCR, portp->crenable); BRDDISABLE(portp->brdnr); portp->tx.tail = portp->tx.head; - restore_flags(flags); + spin_unlock_irqrestore(&brd_lock, flags); } /*****************************************************************************/ @@ -4898,28 +4327,25 @@ static void stl_sc26198flush(stlport_t *portp) * check the port statusy register to be sure. */ -static int stl_sc26198datastate(stlport_t *portp) +static int stl_sc26198datastate(struct stlport *portp) { unsigned long flags; unsigned char sr; -#ifdef DEBUG - printk("stl_sc26198datastate(portp=%x)\n", (int) portp); -#endif + pr_debug("stl_sc26198datastate(portp=%p)\n", portp); - if (portp == (stlport_t *) NULL) - return(0); + if (portp == NULL) + return 0; if (test_bit(ASYI_TXBUSY, &portp->istate)) - return(1); + return 1; - save_flags(flags); - cli(); + spin_lock_irqsave(&brd_lock, flags); BRDENABLE(portp->brdnr, portp->pagenr); sr = stl_sc26198getreg(portp, SR); BRDDISABLE(portp->brdnr); - restore_flags(flags); + spin_unlock_irqrestore(&brd_lock, flags); - return((sr & SR_TXEMPTY) ? 0 : 1); + return (sr & SR_TXEMPTY) ? 0 : 1; } /*****************************************************************************/ @@ -4929,18 +4355,16 @@ static int stl_sc26198datastate(stlport_t *portp) * to process a command... */ -static void stl_sc26198wait(stlport_t *portp) +static void stl_sc26198wait(struct stlport *portp) { int i; -#ifdef DEBUG - printk("stl_sc26198wait(portp=%x)\n", (int) portp); -#endif + pr_debug("stl_sc26198wait(portp=%p)\n", portp); - if (portp == (stlport_t *) NULL) + if (portp == NULL) return; - for (i = 0; (i < 20); i++) + for (i = 0; i < 20; i++) stl_sc26198getglobreg(portp, TSTR); } @@ -4952,7 +4376,7 @@ static void stl_sc26198wait(stlport_t *portp) * automatic flow control modes of the sc26198. */ -static inline void stl_sc26198txunflow(stlport_t *portp, struct tty_struct *tty) +static void stl_sc26198txunflow(struct stlport *portp, struct tty_struct *tty) { unsigned char mr0; @@ -4970,11 +4394,13 @@ static inline void stl_sc26198txunflow(stlport_t *portp, struct tty_struct *tty) * Interrupt service routine for sc26198 panels. */ -static void stl_sc26198intr(stlpanel_t *panelp, unsigned int iobase) +static void stl_sc26198intr(struct stlpanel *panelp, unsigned int iobase) { - stlport_t *portp; + struct stlport *portp; unsigned int iack; + spin_lock(&brd_lock); + /* * Work around bug in sc26198 chip... Cannot have A6 address * line of UART high, else iack will be returned as 0. @@ -4990,6 +4416,8 @@ static void stl_sc26198intr(stlpanel_t *panelp, unsigned int iobase) stl_sc26198txisr(portp); else stl_sc26198otherisr(portp, iack); + + spin_unlock(&brd_lock); } /*****************************************************************************/ @@ -5004,16 +4432,14 @@ static void stl_sc26198intr(stlpanel_t *panelp, unsigned int iobase) * be NULL if the buffer has been freed. */ -static void stl_sc26198txisr(stlport_t *portp) +static void stl_sc26198txisr(struct stlport *portp) { unsigned int ioaddr; unsigned char mr0; int len, stlen; char *head, *tail; -#ifdef DEBUG - printk("stl_sc26198txisr(portp=%x)\n", (int) portp); -#endif + pr_debug("stl_sc26198txisr(portp=%p)\n", portp); ioaddr = portp->ioaddr; head = portp->tx.head; @@ -5038,9 +4464,9 @@ static void stl_sc26198txisr(stlport_t *portp) outb(mr0, (ioaddr + XP_DATA)); } } else { - len = MIN(len, SC26198_TXFIFOSIZE); + len = min(len, SC26198_TXFIFOSIZE); portp->stats.txtotal += len; - stlen = MIN(len, ((portp->tx.buf + STL_TXBUFSIZE) - tail)); + stlen = min(len, ((portp->tx.buf + STL_TXBUFSIZE) - tail)); outb(GTXFIFO, (ioaddr + XP_ADDR)); outsb((ioaddr + XP_DATA), tail, stlen); len -= stlen; @@ -5067,14 +4493,12 @@ static void stl_sc26198txisr(stlport_t *portp) * shutdown a port not in user context. Need to handle this case. */ -static void stl_sc26198rxisr(stlport_t *portp, unsigned int iack) +static void stl_sc26198rxisr(struct stlport *portp, unsigned int iack) { struct tty_struct *tty; unsigned int len, buflen, ioaddr; -#ifdef DEBUG - printk("stl_sc26198rxisr(portp=%x,iack=%x)\n", (int) portp, iack); -#endif + pr_debug("stl_sc26198rxisr(portp=%p,iack=%x)\n", portp, iack); tty = portp->tty; ioaddr = portp->ioaddr; @@ -5082,23 +4506,19 @@ static void stl_sc26198rxisr(stlport_t *portp, unsigned int iack) len = inb(ioaddr + XP_DATA) + 1; if ((iack & IVR_TYPEMASK) == IVR_RXDATA) { - if ((tty == (struct tty_struct *) NULL) || - (tty->flip.char_buf_ptr == (char *) NULL) || - ((buflen = TTY_FLIPBUF_SIZE - tty->flip.count) == 0)) { - len = MIN(len, sizeof(stl_unwanted)); + if (tty == NULL || (buflen = tty_buffer_request_room(tty, len)) == 0) { + len = min(len, sizeof(stl_unwanted)); outb(GRXFIFO, (ioaddr + XP_ADDR)); insb((ioaddr + XP_DATA), &stl_unwanted[0], len); portp->stats.rxlost += len; portp->stats.rxtotal += len; } else { - len = MIN(len, buflen); + len = min(len, buflen); if (len > 0) { + unsigned char *ptr; outb(GRXFIFO, (ioaddr + XP_ADDR)); - insb((ioaddr + XP_DATA), tty->flip.char_buf_ptr, len); - memset(tty->flip.flag_buf_ptr, 0, len); - tty->flip.flag_buf_ptr += len; - tty->flip.char_buf_ptr += len; - tty->flip.count += len; + tty_prepare_flip_string(tty, &ptr, len); + insb((ioaddr + XP_DATA), ptr, len); tty_schedule_flip(tty); portp->stats.rxtotal += len; } @@ -5113,8 +4533,8 @@ static void stl_sc26198rxisr(stlport_t *portp, unsigned int iack) * flow control modes of the sc26198. */ if (test_bit(ASYI_TXFLOWED, &portp->istate)) { - if ((tty != (struct tty_struct *) NULL) && - (tty->termios != (struct termios *) NULL) && + if ((tty != NULL) && + (tty->termios != NULL) && (tty->termios->c_iflag & IXANY)) { stl_sc26198txunflow(portp, tty); } @@ -5127,7 +4547,7 @@ static void stl_sc26198rxisr(stlport_t *portp, unsigned int iack) * Process an RX bad character. */ -static inline void stl_sc26198rxbadch(stlport_t *portp, unsigned char status, char ch) +static void stl_sc26198rxbadch(struct stlport *portp, unsigned char status, char ch) { struct tty_struct *tty; unsigned int ioaddr; @@ -5144,7 +4564,7 @@ static inline void stl_sc26198rxbadch(stlport_t *portp, unsigned char status, ch if (status & SR_RXBREAK) portp->stats.rxbreaks++; - if ((tty != (struct tty_struct *) NULL) && + if ((tty != NULL) && ((portp->rxignoremsk & status) == 0)) { if (portp->rxmarkmsk & status) { if (status & SR_RXBREAK) { @@ -5153,27 +4573,19 @@ static inline void stl_sc26198rxbadch(stlport_t *portp, unsigned char status, ch do_SAK(tty); BRDENABLE(portp->brdnr, portp->pagenr); } - } else if (status & SR_RXPARITY) { + } else if (status & SR_RXPARITY) status = TTY_PARITY; - } else if (status & SR_RXFRAMING) { + else if (status & SR_RXFRAMING) status = TTY_FRAME; - } else if(status & SR_RXOVERRUN) { + else if(status & SR_RXOVERRUN) status = TTY_OVERRUN; - } else { + else status = 0; - } - } else { + } else status = 0; - } - if (tty->flip.char_buf_ptr != (char *) NULL) { - if (tty->flip.count < TTY_FLIPBUF_SIZE) { - *tty->flip.flag_buf_ptr++ = status; - *tty->flip.char_buf_ptr++ = ch; - tty->flip.count++; - } - tty_schedule_flip(tty); - } + tty_insert_flip_char(tty, ch, status); + tty_schedule_flip(tty); if (status == 0) portp->stats.rxtotal++; @@ -5191,7 +4603,7 @@ static inline void stl_sc26198rxbadch(stlport_t *portp, unsigned char status, ch * the FIFO). */ -static void stl_sc26198rxbadchars(stlport_t *portp) +static void stl_sc26198rxbadchars(struct stlport *portp) { unsigned char status, mr1; char ch; @@ -5224,13 +4636,11 @@ static void stl_sc26198rxbadchars(stlport_t *portp) * processing time. */ -static void stl_sc26198otherisr(stlport_t *portp, unsigned int iack) +static void stl_sc26198otherisr(struct stlport *portp, unsigned int iack) { unsigned char cir, ipr, xisr; -#ifdef DEBUG - printk("stl_sc26198otherisr(portp=%x,iack=%x)\n", (int) portp, iack); -#endif + pr_debug("stl_sc26198otherisr(portp=%p,iack=%x)\n", portp, iack); cir = stl_sc26198getglobreg(portp, CIR); @@ -5263,4 +4673,172 @@ static void stl_sc26198otherisr(stlport_t *portp, unsigned int iack) } } -/*****************************************************************************/ +static void stl_free_isabrds(void) +{ + struct stlbrd *brdp; + unsigned int i; + + for (i = 0; i < stl_nrbrds; i++) { + if ((brdp = stl_brds[i]) == NULL || (brdp->state & STL_PROBED)) + continue; + + free_irq(brdp->irq, brdp); + + stl_cleanup_panels(brdp); + + release_region(brdp->ioaddr1, brdp->iosize1); + if (brdp->iosize2 > 0) + release_region(brdp->ioaddr2, brdp->iosize2); + + kfree(brdp); + stl_brds[i] = NULL; + } +} + +/* + * Loadable module initialization stuff. + */ +static int __init stallion_module_init(void) +{ + struct stlbrd *brdp; + struct stlconf conf; + unsigned int i, j; + int retval; + + printk(KERN_INFO "%s: version %s\n", stl_drvtitle, stl_drvversion); + + spin_lock_init(&stallion_lock); + spin_lock_init(&brd_lock); + +/* + * Find any dynamically supported boards. That is via module load + * line options. + */ + for (i = stl_nrbrds; i < stl_nargs; i++) { + memset(&conf, 0, sizeof(conf)); + if (stl_parsebrd(&conf, stl_brdsp[i]) == 0) + continue; + if ((brdp = stl_allocbrd()) == NULL) + continue; + brdp->brdnr = i; + brdp->brdtype = conf.brdtype; + brdp->ioaddr1 = conf.ioaddr1; + brdp->ioaddr2 = conf.ioaddr2; + brdp->irq = conf.irq; + brdp->irqtype = conf.irqtype; + if (stl_brdinit(brdp)) + kfree(brdp); + else { + for (j = 0; j < brdp->nrports; j++) + tty_register_device(stl_serial, + brdp->brdnr * STL_MAXPORTS + j, NULL); + stl_brds[brdp->brdnr] = brdp; + stl_nrbrds = i + 1; + } + } + + /* this has to be _after_ isa finding because of locking */ + retval = pci_register_driver(&stl_pcidriver); + if (retval && stl_nrbrds == 0) + goto err; + + stl_serial = alloc_tty_driver(STL_MAXBRDS * STL_MAXPORTS); + if (!stl_serial) { + retval = -ENOMEM; + goto err_pcidr; + } + +/* + * Set up a character driver for per board stuff. This is mainly used + * to do stats ioctls on the ports. + */ + if (register_chrdev(STL_SIOMEMMAJOR, "staliomem", &stl_fsiomem)) + printk("STALLION: failed to register serial board device\n"); + + stallion_class = class_create(THIS_MODULE, "staliomem"); + if (IS_ERR(stallion_class)) { + retval = PTR_ERR(stallion_class); + goto err_reg; + } + for (i = 0; i < 4; i++) + class_device_create(stallion_class, NULL, + MKDEV(STL_SIOMEMMAJOR, i), NULL, + "staliomem%d", i); + + stl_serial->owner = THIS_MODULE; + stl_serial->driver_name = stl_drvname; + stl_serial->name = "ttyE"; + stl_serial->major = STL_SERIALMAJOR; + stl_serial->minor_start = 0; + stl_serial->type = TTY_DRIVER_TYPE_SERIAL; + stl_serial->subtype = SERIAL_TYPE_NORMAL; + stl_serial->init_termios = stl_deftermios; + stl_serial->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; + tty_set_operations(stl_serial, &stl_ops); + + retval = tty_register_driver(stl_serial); + if (retval) { + printk("STALLION: failed to register serial driver\n"); + goto err_clsdev; + } + + return 0; +err_clsdev: + for (i = 0; i < 4; i++) + class_device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i)); + class_destroy(stallion_class); +err_reg: + unregister_chrdev(STL_SIOMEMMAJOR, "staliomem"); + put_tty_driver(stl_serial); +err_pcidr: + pci_unregister_driver(&stl_pcidriver); + stl_free_isabrds(); +err: + return retval; +} + +static void __exit stallion_module_exit(void) +{ + struct stlbrd *brdp; + unsigned int i, j; + int retval; + + pr_debug("cleanup_module()\n"); + + printk(KERN_INFO "Unloading %s: version %s\n", stl_drvtitle, + stl_drvversion); + +/* + * Free up all allocated resources used by the ports. This includes + * memory and interrupts. As part of this process we will also do + * a hangup on every open port - to try to flush out any processes + * hanging onto ports. + */ + for (i = 0; i < stl_nrbrds; i++) { + if ((brdp = stl_brds[i]) == NULL || (brdp->state & STL_PROBED)) + continue; + for (j = 0; j < brdp->nrports; j++) + tty_unregister_device(stl_serial, + brdp->brdnr * STL_MAXPORTS + j); + } + tty_unregister_driver(stl_serial); + put_tty_driver(stl_serial); + + for (i = 0; i < 4; i++) + class_device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i)); + if ((retval = unregister_chrdev(STL_SIOMEMMAJOR, "staliomem"))) + printk("STALLION: failed to un-register serial memory device, " + "errno=%d\n", -retval); + class_destroy(stallion_class); + + pci_unregister_driver(&stl_pcidriver); + + stl_free_isabrds(); +} + +module_init(stallion_module_init); +module_exit(stallion_module_exit); + +MODULE_AUTHOR("Greg Ungerer"); +MODULE_DESCRIPTION("Stallion Multiport Serial Driver"); +MODULE_LICENSE("GPL");