X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fchar%2Fstallion.c;h=6049fd731924022321f6f2ecf2f7ccf715f23366;hb=5fe7454aa9c6ef5fcf506b0f2dfc20f696891f1a;hp=2db2e9fbb5c6476296a9ed3fb8bb67d8416be7ea;hpb=c62429d93e003043109a0af86cb6bf1da45a1b71;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c index 2db2e9f..6049fd7 100644 --- a/drivers/char/stallion.c +++ b/drivers/char/stallion.c @@ -27,11 +27,13 @@ /*****************************************************************************/ #include +#include #include #include #include #include #include +#include #include #include #include @@ -63,7 +65,7 @@ #define BRD_EASYIOPCI 28 struct stlconf { - int brdtype; + unsigned int brdtype; int ioaddr1; int ioaddr2; unsigned long memaddr; @@ -121,15 +123,6 @@ static struct ktermios stl_deftermios = { }; /* - * 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 struct stlbrd stl_dummybrd; -static struct stlport stl_dummyport; - -/* * Define global place to put buffer overflow characters. */ static char stl_unwanted[SC26198_RXFIFOSIZE]; @@ -139,6 +132,8 @@ static char stl_unwanted[SC26198_RXFIFOSIZE]; static DEFINE_MUTEX(stl_brdslock); static struct stlbrd *stl_brds[STL_MAXBRDS]; +static const struct tty_port_operations stl_port_ops; + /* * Per board state flags. Used with the state field of the board struct. * Not really much here! @@ -154,8 +149,7 @@ static struct stlbrd *stl_brds[STL_MAXBRDS]; */ #define ASYI_TXBUSY 1 #define ASYI_TXLOW 2 -#define ASYI_DCDCHANGE 3 -#define ASYI_TXFLOWED 4 +#define ASYI_TXFLOWED 3 /* * Define an array of board names as printable strings. Handy for @@ -200,7 +194,7 @@ static char *stl_brdnames[] = { * load line. These allow for easy board definitions, and easy * modification of the io, memory and irq resoucres. */ -static int stl_nargs = 0; +static unsigned int stl_nargs; static char *board0[4]; static char *board1[4]; static char *board2[4]; @@ -413,11 +407,10 @@ static unsigned int stl_baudrates[] = { * Declare all those functions in this driver! */ -static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg); +static long stl_memioctl(struct file *fp, unsigned int cmd, unsigned long arg); static int stl_brdinit(struct stlbrd *brdp); -static int stl_getportstats(struct stlport *portp, comstats_t __user *cp); +static int stl_getportstats(struct tty_struct *tty, 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. @@ -614,11 +607,30 @@ static unsigned int sc26198_baudtable[] = { */ static const struct file_operations stl_fsiomem = { .owner = THIS_MODULE, - .ioctl = stl_memioctl, + .unlocked_ioctl = stl_memioctl, }; static struct class *stallion_class; +static void stl_cd_change(struct stlport *portp) +{ + unsigned int oldsigs = portp->sigs; + struct tty_struct *tty = tty_port_tty_get(&portp->port); + + if (!tty) + return; + + portp->sigs = stl_getsignals(portp); + + if ((portp->sigs & TIOCM_CD) && ((oldsigs & TIOCM_CD) == 0)) + wake_up_interruptible(&portp->port.open_wait); + + if ((oldsigs & TIOCM_CD) && ((portp->sigs & TIOCM_CD) == 0)) + if (portp->port.flags & ASYNC_CHECK_CD) + tty_hangup(tty); + tty_kref_put(tty); +} + /* * Check for any arguments passed in on the module load command line. */ @@ -632,7 +644,7 @@ static struct class *stallion_class; static int __init stl_parsebrd(struct stlconf *confp, char **argp) { char *sp; - int i; + unsigned int i; pr_debug("stl_parsebrd(confp=%p,argp=%p)\n", confp, argp); @@ -690,12 +702,30 @@ static struct stlbrd *stl_allocbrd(void) /*****************************************************************************/ +static int stl_activate(struct tty_port *port, struct tty_struct *tty) +{ + struct stlport *portp = container_of(port, struct stlport, port); + 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; + } + stl_setport(portp, tty->termios); + portp->sigs = stl_getsignals(portp); + stl_setsignals(portp, 1, 1); + stl_enablerxtx(portp, 1, 1); + stl_startrxtx(portp, 1, 0); + return 0; +} + static int stl_open(struct tty_struct *tty, struct file *filp) { struct stlport *portp; struct stlbrd *brdp; - unsigned int minordev; - int brdnr, panelnr, portnr, rc; + unsigned int minordev, brdnr, panelnr; + int portnr; pr_debug("stl_open(tty=%p,filp=%p): device=%s\n", tty, filp, tty->name); @@ -706,6 +736,7 @@ static int stl_open(struct tty_struct *tty, struct file *filp) brdp = stl_brds[brdnr]; if (brdp == NULL) return -ENODEV; + minordev = MINOR2PORT(minordev); for (portnr = -1, panelnr = 0; panelnr < STL_MAXPANELS; panelnr++) { if (brdp->panels[panelnr] == NULL) @@ -723,112 +754,24 @@ static int stl_open(struct tty_struct *tty, struct file *filp) if (portp == NULL) return -ENODEV; -/* - * On the first open of the device setup the port hardware, and - * initialize the per port data structure. - */ - portp->tty = tty; tty->driver_data = portp; - portp->refcount++; - - if ((portp->flags & ASYNC_INITIALIZED) == 0) { - 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; - } - stl_setport(portp, tty->termios); - portp->sigs = stl_getsignals(portp); - stl_setsignals(portp, 1, 1); - stl_enablerxtx(portp, 1, 1); - stl_startrxtx(portp, 1, 0); - clear_bit(TTY_IO_ERROR, &tty->flags); - portp->flags |= ASYNC_INITIALIZED; - } - -/* - * Check if this port is in the middle of closing. If so then wait - * until it is closed then return error status, based on flag settings. - * The sleep here does not need interrupt protection since the wakeup - * for it is done with the same context. - */ - if (portp->flags & ASYNC_CLOSING) { - interruptible_sleep_on(&portp->close_wait); - if (portp->flags & ASYNC_HUP_NOTIFY) - return -EAGAIN; - return -ERESTARTSYS; - } + return tty_port_open(&portp->port, tty, filp); -/* - * Based on type of open being done check if it can overlap with any - * 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 ((rc = stl_waitcarrier(portp, filp)) != 0) - return rc; - - portp->flags |= ASYNC_NORMAL_ACTIVE; - - return 0; } /*****************************************************************************/ -/* - * Possibly need to wait for carrier (DCD signal) to come high. Say - * maybe because if we are clocal then we don't need to wait... - */ - -static int stl_waitcarrier(struct stlport *portp, struct file *filp) +static int stl_carrier_raised(struct tty_port *port) { - unsigned long flags; - int rc, doclocal; - - 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++; - - 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)) { - if (portp->flags & ASYNC_HUP_NOTIFY) - rc = -EBUSY; - else - rc = -ERESTARTSYS; - break; - } - if (((portp->flags & ASYNC_CLOSING) == 0) && - (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--; - spin_unlock_irqrestore(&stallion_lock, flags); + struct stlport *portp = container_of(port, struct stlport, port); + return (portp->sigs & TIOCM_CD) ? 1 : 0; +} - return rc; +static void stl_dtr_rts(struct tty_port *port, int on) +{ + struct stlport *portp = container_of(port, struct stlport, port); + /* Takes brd_lock internally */ + stl_setsignals(portp, on, on); } /*****************************************************************************/ @@ -839,8 +782,6 @@ static void stl_flushbuffer(struct tty_struct *tty) pr_debug("stl_flushbuffer(tty=%p)\n", tty); - if (tty == NULL) - return; portp = tty->driver_data; if (portp == NULL) return; @@ -858,8 +799,6 @@ static void stl_waituntilsent(struct tty_struct *tty, int timeout) pr_debug("stl_waituntilsent(tty=%p,timeout=%d)\n", tty, timeout); - if (tty == NULL) - return; portp = tty->driver_data; if (portp == NULL) return; @@ -868,6 +807,7 @@ static void stl_waituntilsent(struct tty_struct *tty, int timeout) timeout = HZ; tend = jiffies + timeout; + lock_kernel(); while (stl_datastate(portp)) { if (signal_pending(current)) break; @@ -875,60 +815,17 @@ static void stl_waituntilsent(struct tty_struct *tty, int timeout) if (time_after_eq(jiffies, tend)) break; } + unlock_kernel(); } /*****************************************************************************/ -static void stl_close(struct tty_struct *tty, struct file *filp) +static void stl_shutdown(struct tty_port *port) { - struct stlport *portp; - unsigned long flags; - - pr_debug("stl_close(tty=%p,filp=%p)\n", tty, filp); - - portp = tty->driver_data; - if (portp == NULL) - return; - - spin_lock_irqsave(&stallion_lock, flags); - if (tty_hung_up_p(filp)) { - spin_unlock_irqrestore(&stallion_lock, flags); - return; - } - if ((tty->count == 1) && (portp->refcount != 1)) - portp->refcount = 1; - if (portp->refcount-- > 1) { - spin_unlock_irqrestore(&stallion_lock, flags); - return; - } - - portp->refcount = 0; - portp->flags |= ASYNC_CLOSING; - -/* - * May want to wait for any data to drain before closing. The BUSY - * flag keeps track of whether we are still sending or not - it is - * very accurate for the cd1400, not quite so for the sc26198. - * (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); - + struct stlport *portp = container_of(port, struct stlport, port); stl_disableintrs(portp); - if (tty->termios->c_cflag & HUPCL) - stl_setsignals(portp, 0, 0); stl_enablerxtx(portp, 0, 0); - stl_flushbuffer(tty); + stl_flush(portp); portp->istate = 0; if (portp->tx.buf != NULL) { kfree(portp->tx.buf); @@ -936,20 +833,17 @@ static void stl_close(struct tty_struct *tty, struct file *filp) portp->tx.head = NULL; portp->tx.tail = NULL; } - set_bit(TTY_IO_ERROR, &tty->flags); - tty_ldisc_flush(tty); - - tty->closing = 0; - portp->tty = NULL; +} - if (portp->openwaitcnt) { - if (portp->close_delay) - msleep_interruptible(jiffies_to_msecs(portp->close_delay)); - wake_up_interruptible(&portp->open_wait); - } +static void stl_close(struct tty_struct *tty, struct file *filp) +{ + struct stlport*portp; + pr_debug("stl_close(tty=%p,filp=%p)\n", tty, filp); - portp->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); - wake_up_interruptible(&portp->close_wait); + portp = tty->driver_data; + if(portp == NULL) + return; + tty_port_close(&portp->port, tty, filp); } /*****************************************************************************/ @@ -1016,7 +910,7 @@ static int stl_write(struct tty_struct *tty, const unsigned char *buf, int count /*****************************************************************************/ -static void stl_putchar(struct tty_struct *tty, unsigned char ch) +static int stl_putchar(struct tty_struct *tty, unsigned char ch) { struct stlport *portp; unsigned int len; @@ -1024,13 +918,11 @@ static void stl_putchar(struct tty_struct *tty, unsigned char ch) pr_debug("stl_putchar(tty=%p,ch=%x)\n", tty, ch); - if (tty == NULL) - return; portp = tty->driver_data; if (portp == NULL) - return; + return -EINVAL; if (portp->tx.buf == NULL) - return; + return -EINVAL; head = portp->tx.head; tail = portp->tx.tail; @@ -1044,6 +936,7 @@ static void stl_putchar(struct tty_struct *tty, unsigned char ch) head = portp->tx.buf; } portp->tx.head = head; + return 0; } /*****************************************************************************/ @@ -1060,8 +953,6 @@ static void stl_flushchars(struct tty_struct *tty) pr_debug("stl_flushchars(tty=%p)\n", tty); - if (tty == NULL) - return; portp = tty->driver_data; if (portp == NULL) return; @@ -1080,8 +971,6 @@ static int stl_writeroom(struct tty_struct *tty) pr_debug("stl_writeroom(tty=%p)\n", tty); - if (tty == NULL) - return 0; portp = tty->driver_data; if (portp == NULL) return 0; @@ -1112,8 +1001,6 @@ static int stl_charsinbuffer(struct tty_struct *tty) pr_debug("stl_charsinbuffer(tty=%p)\n", tty); - if (tty == NULL) - return 0; portp = tty->driver_data; if (portp == NULL) return 0; @@ -1144,7 +1031,7 @@ static int stl_getserial(struct stlport *portp, struct serial_struct __user *sp) memset(&sio, 0, sizeof(struct serial_struct)); sio.line = portp->portnr; sio.port = portp->ioaddr; - sio.flags = portp->flags; + sio.flags = portp->port.flags; sio.baud_base = portp->baud_base; sio.close_delay = portp->close_delay; sio.closing_wait = portp->closing_wait; @@ -1173,8 +1060,9 @@ static int stl_getserial(struct stlport *portp, struct serial_struct __user *sp) * just quietly ignore any requests to change irq, etc. */ -static int stl_setserial(struct stlport *portp, struct serial_struct __user *sp) +static int stl_setserial(struct tty_struct *tty, struct serial_struct __user *sp) { + struct stlport * portp = tty->driver_data; struct serial_struct sio; pr_debug("stl_setserial(portp=%p,sp=%p)\n", portp, sp); @@ -1185,17 +1073,17 @@ static int stl_setserial(struct stlport *portp, struct serial_struct __user *sp) if ((sio.baud_base != portp->baud_base) || (sio.close_delay != portp->close_delay) || ((sio.flags & ~ASYNC_USR_MASK) != - (portp->flags & ~ASYNC_USR_MASK))) + (portp->port.flags & ~ASYNC_USR_MASK))) return -EPERM; } - portp->flags = (portp->flags & ~ASYNC_USR_MASK) | + portp->port.flags = (portp->port.flags & ~ASYNC_USR_MASK) | (sio.flags & ASYNC_USR_MASK); portp->baud_base = sio.baud_base; portp->close_delay = sio.close_delay; portp->closing_wait = sio.closing_wait; portp->custom_divisor = sio.custom_divisor; - stl_setport(portp, portp->tty->termios); + stl_setport(portp, tty->termios); return 0; } @@ -1205,8 +1093,6 @@ static int stl_tiocmget(struct tty_struct *tty, struct file *file) { struct stlport *portp; - if (tty == NULL) - return -ENODEV; portp = tty->driver_data; if (portp == NULL) return -ENODEV; @@ -1222,8 +1108,6 @@ static int stl_tiocmset(struct tty_struct *tty, struct file *file, struct stlport *portp; int rts = -1, dtr = -1; - if (tty == NULL) - return -ENODEV; portp = tty->driver_data; if (portp == NULL) return -ENODEV; @@ -1246,15 +1130,12 @@ 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) { struct stlport *portp; - unsigned int ival; int rc; void __user *argp = (void __user *)arg; pr_debug("stl_ioctl(tty=%p,file=%p,cmd=%x,arg=%lx)\n", tty, file, cmd, arg); - if (tty == NULL) - return -ENODEV; portp = tty->driver_data; if (portp == NULL) return -ENODEV; @@ -1266,26 +1147,17 @@ static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd rc = 0; + lock_kernel(); + switch (cmd) { - case TIOCGSOFTCAR: - rc = put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0), - (unsigned __user *) argp); - break; - case TIOCSSOFTCAR: - if (get_user(ival, (unsigned int __user *) arg)) - return -EFAULT; - tty->termios->c_cflag = - (tty->termios->c_cflag & ~CLOCAL) | - (ival ? CLOCAL : 0); - break; case TIOCGSERIAL: rc = stl_getserial(portp, argp); break; case TIOCSSERIAL: - rc = stl_setserial(portp, argp); + rc = stl_setserial(tty, argp); break; case COM_GETPORTSTATS: - rc = stl_getportstats(portp, argp); + rc = stl_getportstats(tty, portp, argp); break; case COM_CLRPORTSTATS: rc = stl_clrportstats(portp, argp); @@ -1301,7 +1173,7 @@ static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd rc = -ENOIOCTLCMD; break; } - + unlock_kernel(); return rc; } @@ -1317,8 +1189,6 @@ static void stl_start(struct tty_struct *tty) pr_debug("stl_start(tty=%p)\n", tty); - if (tty == NULL) - return; portp = tty->driver_data; if (portp == NULL) return; @@ -1334,8 +1204,6 @@ static void stl_settermios(struct tty_struct *tty, struct ktermios *old) pr_debug("stl_settermios(tty=%p,old=%p)\n", tty, old); - if (tty == NULL) - return; portp = tty->driver_data; if (portp == NULL) return; @@ -1353,7 +1221,7 @@ static void stl_settermios(struct tty_struct *tty, struct ktermios *old) stl_start(tty); } if (((old->c_cflag & CLOCAL) == 0) && (tiosp->c_cflag & CLOCAL)) - wake_up_interruptible(&portp->open_wait); + wake_up_interruptible(&portp->port.open_wait); } /*****************************************************************************/ @@ -1369,8 +1237,6 @@ static void stl_throttle(struct tty_struct *tty) pr_debug("stl_throttle(tty=%p)\n", tty); - if (tty == NULL) - return; portp = tty->driver_data; if (portp == NULL) return; @@ -1389,8 +1255,6 @@ static void stl_unthrottle(struct tty_struct *tty) pr_debug("stl_unthrottle(tty=%p)\n", tty); - if (tty == NULL) - return; portp = tty->driver_data; if (portp == NULL) return; @@ -1410,8 +1274,6 @@ static void stl_stop(struct tty_struct *tty) pr_debug("stl_stop(tty=%p)\n", tty); - if (tty == NULL) - return; portp = tty->driver_data; if (portp == NULL) return; @@ -1428,51 +1290,28 @@ static void stl_stop(struct tty_struct *tty) static void stl_hangup(struct tty_struct *tty) { - struct stlport *portp; - + struct stlport *portp = tty->driver_data; pr_debug("stl_hangup(tty=%p)\n", tty); - if (tty == NULL) - return; - portp = tty->driver_data; if (portp == NULL) return; - - portp->flags &= ~ASYNC_INITIALIZED; - 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; - set_bit(TTY_IO_ERROR, &tty->flags); - if (portp->tx.buf != NULL) { - kfree(portp->tx.buf); - portp->tx.buf = NULL; - portp->tx.head = NULL; - portp->tx.tail = NULL; - } - portp->tty = NULL; - portp->flags &= ~ASYNC_NORMAL_ACTIVE; - portp->refcount = 0; - wake_up_interruptible(&portp->open_wait); + tty_port_hangup(&portp->port); } /*****************************************************************************/ -static void stl_breakctl(struct tty_struct *tty, int state) +static int stl_breakctl(struct tty_struct *tty, int state) { struct stlport *portp; pr_debug("stl_breakctl(tty=%p,state=%d)\n", tty, state); - if (tty == NULL) - return; portp = tty->driver_data; if (portp == NULL) - return; + return -EINVAL; stl_sendbreak(portp, ((state == -1) ? 1 : 2)); + return 0; } /*****************************************************************************/ @@ -1483,8 +1322,6 @@ static void stl_sendxchar(struct tty_struct *tty, char ch) pr_debug("stl_sendxchar(tty=%p,ch=%x)\n", tty, ch); - if (tty == NULL) - return; portp = tty->driver_data; if (portp == NULL) return; @@ -1497,52 +1334,47 @@ static void stl_sendxchar(struct tty_struct *tty, char ch) stl_putchar(tty, ch); } -/*****************************************************************************/ - -#define MAXLINE 80 - -/* - * Format info for a specified port. The line is deliberately limited - * to 80 characters. (If it is too long it will be truncated, if too - * short then padded with spaces). - */ - -static int stl_portinfo(struct stlport *portp, int portnr, char *pos) +static void stl_portinfo(struct seq_file *m, struct stlport *portp, int portnr) { - char *sp; - int sigs, cnt; + int sigs; + char sep; - sp = pos; - sp += sprintf(sp, "%d: uart:%s tx:%d rx:%d", + seq_printf(m, "%d: uart:%s tx:%d rx:%d", portnr, (portp->hwid == 1) ? "SC26198" : "CD1400", (int) portp->stats.txtotal, (int) portp->stats.rxtotal); if (portp->stats.rxframing) - sp += sprintf(sp, " fe:%d", (int) portp->stats.rxframing); + seq_printf(m, " fe:%d", (int) portp->stats.rxframing); if (portp->stats.rxparity) - sp += sprintf(sp, " pe:%d", (int) portp->stats.rxparity); + seq_printf(m, " pe:%d", (int) portp->stats.rxparity); if (portp->stats.rxbreaks) - sp += sprintf(sp, " brk:%d", (int) portp->stats.rxbreaks); + seq_printf(m, " brk:%d", (int) portp->stats.rxbreaks); if (portp->stats.rxoverrun) - sp += sprintf(sp, " oe:%d", (int) portp->stats.rxoverrun); + seq_printf(m, " oe:%d", (int) portp->stats.rxoverrun); sigs = stl_getsignals(portp); - cnt = sprintf(sp, "%s%s%s%s%s ", - (sigs & TIOCM_RTS) ? "|RTS" : "", - (sigs & TIOCM_CTS) ? "|CTS" : "", - (sigs & TIOCM_DTR) ? "|DTR" : "", - (sigs & TIOCM_CD) ? "|DCD" : "", - (sigs & TIOCM_DSR) ? "|DSR" : ""); - *sp = ' '; - sp += cnt; - - for (cnt = sp - pos; cnt < (MAXLINE - 1); cnt++) - *sp++ = ' '; - if (cnt >= MAXLINE) - pos[(MAXLINE - 2)] = '+'; - pos[(MAXLINE - 1)] = '\n'; - - return MAXLINE; + sep = ' '; + if (sigs & TIOCM_RTS) { + seq_printf(m, "%c%s", sep, "RTS"); + sep = '|'; + } + if (sigs & TIOCM_CTS) { + seq_printf(m, "%c%s", sep, "CTS"); + sep = '|'; + } + if (sigs & TIOCM_DTR) { + seq_printf(m, "%c%s", sep, "DTR"); + sep = '|'; + } + if (sigs & TIOCM_CD) { + seq_printf(m, "%c%s", sep, "DCD"); + sep = '|'; + } + if (sigs & TIOCM_DSR) { + seq_printf(m, "%c%s", sep, "DSR"); + sep = '|'; + } + seq_putc(m, '\n'); } /*****************************************************************************/ @@ -1551,30 +1383,17 @@ static int stl_portinfo(struct stlport *portp, int portnr, char *pos) * Port info, read from the /proc file system. */ -static int stl_readproc(char *page, char **start, off_t off, int count, int *eof, void *data) +static int stl_proc_show(struct seq_file *m, void *v) { struct stlbrd *brdp; struct stlpanel *panelp; struct stlport *portp; - int brdnr, panelnr, portnr, totalport; - int curoff, maxoff; - char *pos; - - pr_debug("stl_readproc(page=%p,start=%p,off=%lx,count=%d,eof=%p," - "data=%p\n", page, start, off, count, eof, data); + unsigned int brdnr, panelnr, portnr; + int totalport; - pos = page; totalport = 0; - curoff = 0; - - if (off == 0) { - pos += sprintf(pos, "%s: version %s", stl_drvtitle, - stl_drvversion); - while (pos < (page + MAXLINE - 1)) - *pos++ = ' '; - *pos++ = '\n'; - } - curoff = MAXLINE; + + seq_printf(m, "%s: version %s\n", stl_drvtitle, stl_drvversion); /* * We scan through for each board, panel and port. The offset is @@ -1587,46 +1406,37 @@ static int stl_readproc(char *page, char **start, off_t off, int count, int *eof if (brdp->state == 0) continue; - maxoff = curoff + (brdp->nrports * MAXLINE); - if (off >= maxoff) { - curoff = maxoff; - continue; - } - totalport = brdnr * STL_MAXPORTS; for (panelnr = 0; panelnr < brdp->nrpanels; panelnr++) { panelp = brdp->panels[panelnr]; if (panelp == NULL) continue; - maxoff = curoff + (panelp->nrports * MAXLINE); - if (off >= maxoff) { - curoff = maxoff; - totalport += panelp->nrports; - continue; - } - for (portnr = 0; portnr < panelp->nrports; portnr++, totalport++) { portp = panelp->ports[portnr]; if (portp == NULL) continue; - if (off >= (curoff += MAXLINE)) - continue; - if ((pos - page + MAXLINE) > count) - goto stl_readdone; - pos += stl_portinfo(portp, totalport, pos); + stl_portinfo(m, portp, totalport); } } } + return 0; +} - *eof = 1; - -stl_readdone: - *start = page; - return pos - page; +static int stl_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, stl_proc_show, NULL); } +static const struct file_operations stl_proc_fops = { + .owner = THIS_MODULE, + .open = stl_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + /*****************************************************************************/ /* @@ -1638,7 +1448,7 @@ static irqreturn_t stl_intr(int irq, void *dev_id) { struct stlbrd *brdp = dev_id; - pr_debug("stl_intr(brdp=%p,irq=%d)\n", brdp, irq); + pr_debug("stl_intr(brdp=%p,irq=%d)\n", brdp, brdp->irq); return IRQ_RETVAL((* brdp->isr)(brdp)); } @@ -1675,8 +1485,7 @@ static int stl_eiointr(struct stlbrd *brdp) static int stl_echatintr(struct stlbrd *brdp) { struct stlpanel *panelp; - unsigned int ioaddr; - int bnknr; + unsigned int ioaddr, bnknr; int handled = 0; outb((brdp->ioctrlval | ECH_BRDENABLE), brdp->ioctrl); @@ -1706,8 +1515,7 @@ static int stl_echatintr(struct stlbrd *brdp) static int stl_echmcaintr(struct stlbrd *brdp) { struct stlpanel *panelp; - unsigned int ioaddr; - int bnknr; + unsigned int ioaddr, bnknr; int handled = 0; while (inb(brdp->iostatus) & ECH_INTRPEND) { @@ -1732,8 +1540,7 @@ static int stl_echmcaintr(struct stlbrd *brdp) static int stl_echpciintr(struct stlbrd *brdp) { struct stlpanel *panelp; - unsigned int ioaddr; - int bnknr, recheck; + unsigned int ioaddr, bnknr, recheck; int handled = 0; while (1) { @@ -1763,8 +1570,7 @@ static int stl_echpciintr(struct stlbrd *brdp) static int stl_echpci64intr(struct stlbrd *brdp) { struct stlpanel *panelp; - unsigned int ioaddr; - int bnknr; + unsigned int ioaddr, bnknr; int handled = 0; while (inb(brdp->ioctrl) & 0x1) { @@ -1784,50 +1590,14 @@ static int stl_echpci64intr(struct stlbrd *brdp) /*****************************************************************************/ /* - * Service an off-level request for some channel. - */ -static void stl_offintr(struct work_struct *work) -{ - struct stlport *portp = container_of(work, struct stlport, tqueue); - struct tty_struct *tty; - unsigned int oldsigs; - - pr_debug("stl_offintr(portp=%p)\n", portp); - - if (portp == NULL) - return; - - tty = portp->tty; - if (tty == NULL) - return; - - lock_kernel(); - 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 (portp->flags & ASYNC_CHECK_CD) - tty_hangup(tty); /* FIXME: module removal race here - AKPM */ - } - unlock_kernel(); -} - -/*****************************************************************************/ - -/* * Initialize all the ports on a panel. */ static int __devinit stl_initports(struct stlbrd *brdp, struct stlpanel *panelp) { - struct stlport *portp; - int chipmask, i; + struct stlport *portp; + unsigned int i; + int chipmask; pr_debug("stl_initports(brdp=%p,panelp=%p)\n", brdp, panelp); @@ -1844,7 +1614,8 @@ static int __devinit stl_initports(struct stlbrd *brdp, struct stlpanel *panelp) "(size=%Zd)\n", sizeof(struct stlport)); break; } - + tty_port_init(&portp->port); + portp->port.ops = &stl_port_ops; portp->magic = STL_PORTMAGIC; portp->portnr = i; portp->brdnr = panelp->brdnr; @@ -1854,9 +1625,8 @@ static int __devinit stl_initports(struct stlbrd *brdp, struct stlpanel *panelp) portp->baud_base = STL_BAUDBASE; portp->close_delay = STL_CLOSEDELAY; portp->closing_wait = 30 * HZ; - INIT_WORK(&portp->tqueue, stl_offintr); - init_waitqueue_head(&portp->open_wait); - init_waitqueue_head(&portp->close_wait); + init_waitqueue_head(&portp->port.open_wait); + init_waitqueue_head(&portp->port.close_wait); portp->stats.brd = portp->brdnr; portp->stats.panel = portp->panelnr; portp->stats.port = portp->portnr; @@ -1872,6 +1642,7 @@ static void stl_cleanup_panels(struct stlbrd *brdp) struct stlpanel *panelp; struct stlport *portp; unsigned int j, k; + struct tty_struct *tty; for (j = 0; j < STL_MAXPANELS; j++) { panelp = brdp->panels[j]; @@ -1881,8 +1652,11 @@ static void stl_cleanup_panels(struct stlbrd *brdp) portp = panelp->ports[k]; if (portp == NULL) continue; - if (portp->tty != NULL) - stl_hangup(portp->tty); + tty = tty_port_tty_get(&portp->port); + if (tty != NULL) { + stl_hangup(tty); + tty_kref_put(tty); + } kfree(portp->tx.buf); kfree(portp); } @@ -2052,8 +1826,8 @@ err: static int __devinit stl_initech(struct stlbrd *brdp) { struct stlpanel *panelp; - unsigned int status, nxtid, ioaddr, conflict; - int panelnr, banknr, i, retval; + unsigned int status, nxtid, ioaddr, conflict, panelnr, banknr, i; + int retval; char *name; pr_debug("stl_initech(brdp=%p)\n", brdp); @@ -2184,11 +1958,12 @@ static int __devinit stl_initech(struct stlbrd *brdp) } status = inb(ioaddr + ECH_PNLSTATUS); if ((status & ECH_PNLIDMASK) != nxtid) - goto err_fr; + break; panelp = kzalloc(sizeof(struct stlpanel), GFP_KERNEL); if (!panelp) { printk("STALLION: failed to allocate memory " "(size=%Zd)\n", sizeof(struct stlpanel)); + retval = -ENOMEM; goto err_fr; } panelp->magic = STL_PANELMAGIC; @@ -2235,8 +2010,10 @@ static int __devinit stl_initech(struct stlbrd *brdp) brdp->nrports += panelp->nrports; brdp->panels[panelnr++] = panelp; if ((brdp->brdtype != BRD_ECHPCI) && - (ioaddr >= (brdp->ioaddr2 + brdp->iosize2))) + (ioaddr >= (brdp->ioaddr2 + brdp->iosize2))) { + retval = -EINVAL; goto err_fr; + } } brdp->nrpanels = panelnr; @@ -2337,7 +2114,7 @@ err: static int __devinit stl_getbrdnr(void) { - int i; + unsigned int i; for (i = 0; i < STL_MAXBRDS; i++) if (stl_brds[i] == NULL) { @@ -2360,15 +2137,12 @@ static int __devinit stl_pciprobe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct stlbrd *brdp; - unsigned int brdtype = ent->driver_data; - int retval = -ENODEV; + 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; @@ -2378,13 +2152,15 @@ static int __devinit stl_pciprobe(struct pci_dev *pdev, goto err; } mutex_lock(&stl_brdslock); - brdp->brdnr = stl_getbrdnr(); - if (brdp->brdnr < 0) { + brdnr = stl_getbrdnr(); + if (brdnr < 0) { dev_err(&pdev->dev, "too many boards found, " "maximum supported %d\n", STL_MAXBRDS); mutex_unlock(&stl_brdslock); + retval = -ENODEV; goto err_fr; } + brdp->brdnr = (unsigned int)brdnr; stl_brds[brdp->brdnr] = brdp; mutex_unlock(&stl_brdslock); @@ -2420,6 +2196,10 @@ static int __devinit stl_pciprobe(struct pci_dev *pdev, pci_set_drvdata(pdev, brdp); + for (i = 0; i < brdp->nrports; i++) + tty_register_device(stl_serial, + brdp->brdnr * STL_MAXPORTS + i, &pdev->dev); + return 0; err_null: stl_brds[brdp->brdnr] = NULL; @@ -2432,6 +2212,7 @@ err: static void __devexit stl_pciremove(struct pci_dev *pdev) { struct stlbrd *brdp = pci_get_drvdata(pdev); + unsigned int i; free_irq(brdp->irq, brdp); @@ -2441,6 +2222,10 @@ static void __devexit stl_pciremove(struct pci_dev *pdev) if (brdp->iosize2 > 0) release_region(brdp->ioaddr2, brdp->iosize2); + for (i = 0; i < brdp->nrports; i++) + tty_unregister_device(stl_serial, + brdp->brdnr * STL_MAXPORTS + i); + stl_brds[brdp->brdnr] = NULL; kfree(brdp); } @@ -2460,9 +2245,10 @@ static struct pci_driver stl_pcidriver = { static int stl_getbrdstats(combrd_t __user *bp) { + combrd_t stl_brdstats; struct stlbrd *brdp; struct stlpanel *panelp; - int i; + unsigned int i; if (copy_from_user(&stl_brdstats, bp, sizeof(combrd_t))) return -EFAULT; @@ -2508,12 +2294,12 @@ static struct stlport *stl_getport(int brdnr, int panelnr, int portnr) brdp = stl_brds[brdnr]; if (brdp == NULL) return NULL; - if (panelnr < 0 || panelnr >= brdp->nrpanels) + if (panelnr < 0 || (unsigned int)panelnr >= brdp->nrpanels) return NULL; panelp = brdp->panels[panelnr]; if (panelp == NULL) return NULL; - if (portnr < 0 || portnr >= panelp->nrports) + if (portnr < 0 || (unsigned int)portnr >= panelp->nrports) return NULL; return panelp->ports[portnr]; } @@ -2526,8 +2312,9 @@ static struct stlport *stl_getport(int brdnr, int panelnr, int portnr) * what port to get stats for (used through board control device). */ -static int stl_getportstats(struct stlport *portp, comstats_t __user *cp) +static int stl_getportstats(struct tty_struct *tty, struct stlport *portp, comstats_t __user *cp) { + comstats_t stl_comstats; unsigned char *head, *tail; unsigned long flags; @@ -2541,7 +2328,7 @@ static int stl_getportstats(struct stlport *portp, comstats_t __user *cp) } portp->stats.state = portp->istate; - portp->stats.flags = portp->flags; + portp->stats.flags = portp->port.flags; portp->stats.hwid = portp->hwid; portp->stats.ttystate = 0; @@ -2552,18 +2339,17 @@ static int stl_getportstats(struct stlport *portp, comstats_t __user *cp) portp->stats.rxbuffered = 0; spin_lock_irqsave(&stallion_lock, flags); - if (portp->tty != NULL) - if (portp->tty->driver_data == portp) { - portp->stats.ttystate = portp->tty->flags; - /* 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; - } + if (tty != NULL && portp->port.tty == tty) { + portp->stats.ttystate = tty->flags; + /* No longer available as a statistic */ + portp->stats.rxbuffered = 1; /*tty->flip.count; */ + if (tty->termios != NULL) { + portp->stats.cflags = tty->termios->c_cflag; + portp->stats.iflags = tty->termios->c_iflag; + portp->stats.oflags = tty->termios->c_oflag; + portp->stats.lflags = tty->termios->c_lflag; } + } spin_unlock_irqrestore(&stallion_lock, flags); head = portp->tx.head; @@ -2585,6 +2371,8 @@ static int stl_getportstats(struct stlport *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; @@ -2610,6 +2398,7 @@ static int stl_clrportstats(struct stlport *portp, comstats_t __user *cp) static int stl_getportstruct(struct stlport __user *arg) { + struct stlport stl_dummyport; struct stlport *portp; if (copy_from_user(&stl_dummyport, arg, sizeof(struct stlport))) @@ -2629,11 +2418,12 @@ static int stl_getportstruct(struct stlport __user *arg) static int stl_getbrdstruct(struct stlbrd __user *arg) { + struct stlbrd stl_dummybrd; struct stlbrd *brdp; 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) @@ -2649,21 +2439,22 @@ static int stl_getbrdstruct(struct stlbrd __user *arg) * collection. */ -static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg) +static long stl_memioctl(struct file *fp, unsigned int cmd, unsigned long arg) { int brdnr, rc; void __user *argp = (void __user *)arg; - pr_debug("stl_memioctl(ip=%p,fp=%p,cmd=%x,arg=%lx)\n", ip, fp, cmd,arg); + pr_debug("stl_memioctl(fp=%p,cmd=%x,arg=%lx)\n", fp, cmd,arg); - brdnr = iminor(ip); + brdnr = iminor(fp->f_dentry->d_inode); if (brdnr >= STL_MAXBRDS) return -ENODEV; rc = 0; + lock_kernel(); switch (cmd) { case COM_GETPORTSTATS: - rc = stl_getportstats(NULL, argp); + rc = stl_getportstats(NULL, NULL, argp); break; case COM_CLRPORTSTATS: rc = stl_clrportstats(NULL, argp); @@ -2681,7 +2472,7 @@ static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, uns rc = -ENOIOCTLCMD; break; } - + unlock_kernel(); return rc; } @@ -2704,9 +2495,16 @@ static const struct tty_operations stl_ops = { .break_ctl = stl_breakctl, .wait_until_sent = stl_waituntilsent, .send_xchar = stl_sendxchar, - .read_proc = stl_readproc, .tiocmget = stl_tiocmget, .tiocmset = stl_tiocmset, + .proc_fops = &stl_proc_fops, +}; + +static const struct tty_port_operations stl_port_ops = { + .carrier_raised = stl_carrier_raised, + .dtr_rts = stl_dtr_rts, + .activate = stl_activate, + .shutdown = stl_shutdown, }; /*****************************************************************************/ @@ -2963,15 +2761,15 @@ static void stl_cd1400setport(struct stlport *portp, struct ktermios *tiosp) } baudrate = stl_baudrates[baudrate]; if ((tiosp->c_cflag & CBAUD) == B38400) { - if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) baudrate = 57600; - else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + else if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) baudrate = 115200; - else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + else if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) baudrate = 230400; - else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + else if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) baudrate = 460800; - else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) + else if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) baudrate = (portp->baud_base / portp->custom_divisor); } if (baudrate > STL_CD1400MAXBAUD) @@ -2993,9 +2791,9 @@ static void stl_cd1400setport(struct stlport *portp, struct ktermios *tiosp) mcor1 |= MCOR1_DCD; mcor2 |= MCOR2_DCD; sreron |= SRER_MODEM; - portp->flags |= ASYNC_CHECK_CD; + portp->port.flags |= ASYNC_CHECK_CD; } else - portp->flags &= ~ASYNC_CHECK_CD; + portp->port.flags &= ~ASYNC_CHECK_CD; /* * Setup cd1400 enhanced modes if we can. In particular we want to @@ -3266,7 +3064,7 @@ static void stl_cd1400flowctrl(struct stlport *portp, int state) if (portp == NULL) return; - tty = portp->tty; + tty = tty_port_tty_get(&portp->port); if (tty == NULL) return; @@ -3311,6 +3109,7 @@ static void stl_cd1400flowctrl(struct stlport *portp, int state) BRDDISABLE(portp->brdnr); spin_unlock_irqrestore(&brd_lock, flags); + tty_kref_put(tty); } /*****************************************************************************/ @@ -3328,7 +3127,7 @@ static void stl_cd1400sendflow(struct stlport *portp, int state) if (portp == NULL) return; - tty = portp->tty; + tty = tty_port_tty_get(&portp->port); if (tty == NULL) return; @@ -3348,6 +3147,7 @@ static void stl_cd1400sendflow(struct stlport *portp, int state) } BRDDISABLE(portp->brdnr); spin_unlock_irqrestore(&brd_lock, flags); + tty_kref_put(tty); } /*****************************************************************************/ @@ -3501,6 +3301,7 @@ static void stl_cd1400txisr(struct stlpanel *panelp, int ioaddr) int len, stlen; char *head, *tail; unsigned char ioack, srer; + struct tty_struct *tty; pr_debug("stl_cd1400txisr(panelp=%p,ioaddr=%x)\n", panelp, ioaddr); @@ -3527,7 +3328,11 @@ static void stl_cd1400txisr(struct stlpanel *panelp, int ioaddr) if ((len == 0) || ((len < STL_TXBUFLOW) && (test_bit(ASYI_TXLOW, &portp->istate) == 0))) { set_bit(ASYI_TXLOW, &portp->istate); - schedule_work(&portp->tqueue); + tty = tty_port_tty_get(&portp->port); + if (tty) { + tty_wakeup(tty); + tty_kref_put(tty); + } } if (len == 0) { @@ -3543,7 +3348,8 @@ static void stl_cd1400txisr(struct stlpanel *panelp, int ioaddr) } else { len = min(len, CD1400_TXFIFOSIZE); portp->stats.txtotal += len; - stlen = min(len, ((portp->tx.buf + STL_TXBUFSIZE) - tail)); + stlen = min_t(unsigned int, len, + (portp->tx.buf + STL_TXBUFSIZE) - tail); outb((TDR + portp->uartaddr), ioaddr); outsb((ioaddr + EREG_DATA), tail, stlen); len -= stlen; @@ -3590,13 +3396,13 @@ static void stl_cd1400rxisr(struct stlpanel *panelp, int ioaddr) return; } portp = panelp->ports[(ioack >> 3)]; - tty = portp->tty; + tty = tty_port_tty_get(&portp->port); if ((ioack & ACK_TYPMASK) == ACK_TYPRXGOOD) { outb((RDCR + portp->uartaddr), ioaddr); len = inb(ioaddr + EREG_DATA); if (tty == NULL || (buflen = tty_buffer_request_room(tty, len)) == 0) { - len = min(len, sizeof(stl_unwanted)); + len = min_t(unsigned int, len, sizeof(stl_unwanted)); outb((RDSR + portp->uartaddr), ioaddr); insb((ioaddr + EREG_DATA), &stl_unwanted[0], len); portp->stats.rxlost += len; @@ -3635,7 +3441,7 @@ static void stl_cd1400rxisr(struct stlpanel *panelp, int ioaddr) if (portp->rxmarkmsk & status) { if (status & ST_BREAK) { status = TTY_BREAK; - if (portp->flags & ASYNC_SAK) { + if (portp->port.flags & ASYNC_SAK) { do_SAK(tty); BRDENABLE(portp->brdnr, portp->pagenr); } @@ -3654,10 +3460,12 @@ static void stl_cd1400rxisr(struct stlpanel *panelp, int ioaddr) } } else { printk("STALLION: bad RX interrupt ack value=%x\n", ioack); + tty_kref_put(tty); return; } stl_rxalldone: + tty_kref_put(tty); outb((EOSRR + portp->uartaddr), ioaddr); outb(0, (ioaddr + EREG_DATA)); } @@ -3689,8 +3497,7 @@ static void stl_cd1400mdmisr(struct stlpanel *panelp, int ioaddr) outb((MISR + portp->uartaddr), ioaddr); misr = inb(ioaddr + EREG_DATA); if (misr & MISR_DCD) { - set_bit(ASYI_DCDCHANGE, &portp->istate); - schedule_work(&portp->tqueue); + stl_cd_change(portp); portp->stats.modem++; } @@ -3922,15 +3729,15 @@ static void stl_sc26198setport(struct stlport *portp, struct ktermios *tiosp) } baudrate = stl_baudrates[baudrate]; if ((tiosp->c_cflag & CBAUD) == B38400) { - if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) baudrate = 57600; - else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + else if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) baudrate = 115200; - else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + else if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) baudrate = 230400; - else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + else if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) baudrate = 460800; - else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) + else if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) baudrate = (portp->baud_base / portp->custom_divisor); } if (baudrate > STL_SC26198MAXBAUD) @@ -3945,11 +3752,11 @@ static void stl_sc26198setport(struct stlport *portp, struct ktermios *tiosp) * Check what form of modem signaling is required and set it up. */ if (tiosp->c_cflag & CLOCAL) { - portp->flags &= ~ASYNC_CHECK_CD; + portp->port.flags &= ~ASYNC_CHECK_CD; } else { iopr |= IOPR_DCDCOS; imron |= IR_IOPORT; - portp->flags |= ASYNC_CHECK_CD; + portp->port.flags |= ASYNC_CHECK_CD; } /* @@ -4197,7 +4004,7 @@ static void stl_sc26198flowctrl(struct stlport *portp, int state) if (portp == NULL) return; - tty = portp->tty; + tty = tty_port_tty_get(&portp->port); if (tty == NULL) return; @@ -4248,6 +4055,7 @@ static void stl_sc26198flowctrl(struct stlport *portp, int state) BRDDISABLE(portp->brdnr); spin_unlock_irqrestore(&brd_lock, flags); + tty_kref_put(tty); } /*****************************************************************************/ @@ -4266,7 +4074,7 @@ static void stl_sc26198sendflow(struct stlport *portp, int state) if (portp == NULL) return; - tty = portp->tty; + tty = tty_port_tty_get(&portp->port); if (tty == NULL) return; @@ -4291,6 +4099,7 @@ static void stl_sc26198sendflow(struct stlport *portp, int state) } BRDDISABLE(portp->brdnr); spin_unlock_irqrestore(&brd_lock, flags); + tty_kref_put(tty); } /*****************************************************************************/ @@ -4430,6 +4239,7 @@ static void stl_sc26198intr(struct stlpanel *panelp, unsigned int iobase) static void stl_sc26198txisr(struct stlport *portp) { + struct tty_struct *tty; unsigned int ioaddr; unsigned char mr0; int len, stlen; @@ -4444,7 +4254,11 @@ static void stl_sc26198txisr(struct stlport *portp) if ((len == 0) || ((len < STL_TXBUFLOW) && (test_bit(ASYI_TXLOW, &portp->istate) == 0))) { set_bit(ASYI_TXLOW, &portp->istate); - schedule_work(&portp->tqueue); + tty = tty_port_tty_get(&portp->port); + if (tty) { + tty_wakeup(tty); + tty_kref_put(tty); + } } if (len == 0) { @@ -4462,7 +4276,8 @@ static void stl_sc26198txisr(struct stlport *portp) } else { len = min(len, SC26198_TXFIFOSIZE); portp->stats.txtotal += len; - stlen = min(len, ((portp->tx.buf + STL_TXBUFSIZE) - tail)); + stlen = min_t(unsigned int, len, + (portp->tx.buf + STL_TXBUFSIZE) - tail); outb(GTXFIFO, (ioaddr + XP_ADDR)); outsb((ioaddr + XP_DATA), tail, stlen); len -= stlen; @@ -4496,14 +4311,14 @@ static void stl_sc26198rxisr(struct stlport *portp, unsigned int iack) pr_debug("stl_sc26198rxisr(portp=%p,iack=%x)\n", portp, iack); - tty = portp->tty; + tty = tty_port_tty_get(&portp->port); ioaddr = portp->ioaddr; outb(GIBCR, (ioaddr + XP_ADDR)); len = inb(ioaddr + XP_DATA) + 1; if ((iack & IVR_TYPEMASK) == IVR_RXDATA) { if (tty == NULL || (buflen = tty_buffer_request_room(tty, len)) == 0) { - len = min(len, sizeof(stl_unwanted)); + len = min_t(unsigned int, len, sizeof(stl_unwanted)); outb(GRXFIFO, (ioaddr + XP_ADDR)); insb((ioaddr + XP_DATA), &stl_unwanted[0], len); portp->stats.rxlost += len; @@ -4535,6 +4350,7 @@ static void stl_sc26198rxisr(struct stlport *portp, unsigned int iack) stl_sc26198txunflow(portp, tty); } } + tty_kref_put(tty); } /*****************************************************************************/ @@ -4548,7 +4364,7 @@ static void stl_sc26198rxbadch(struct stlport *portp, unsigned char status, char struct tty_struct *tty; unsigned int ioaddr; - tty = portp->tty; + tty = tty_port_tty_get(&portp->port); ioaddr = portp->ioaddr; if (status & SR_RXPARITY) @@ -4565,7 +4381,7 @@ static void stl_sc26198rxbadch(struct stlport *portp, unsigned char status, char if (portp->rxmarkmsk & status) { if (status & SR_RXBREAK) { status = TTY_BREAK; - if (portp->flags & ASYNC_SAK) { + if (portp->port.flags & ASYNC_SAK) { do_SAK(tty); BRDENABLE(portp->brdnr, portp->pagenr); } @@ -4586,6 +4402,7 @@ static void stl_sc26198rxbadch(struct stlport *portp, unsigned char status, char if (status == 0) portp->stats.rxtotal++; } + tty_kref_put(tty); } /*****************************************************************************/ @@ -4644,8 +4461,7 @@ static void stl_sc26198otherisr(struct stlport *portp, unsigned int iack) case CIR_SUBCOS: ipr = stl_sc26198getreg(portp, IPR); if (ipr & IPR_DCDCHANGE) { - set_bit(ASYI_DCDCHANGE, &portp->istate); - schedule_work(&portp->tqueue); + stl_cd_change(portp); portp->stats.modem++; } break; @@ -4698,7 +4514,7 @@ static int __init stallion_module_init(void) { struct stlbrd *brdp; struct stlconf conf; - unsigned int i; + unsigned int i, j; int retval; printk(KERN_INFO "%s: version %s\n", stl_drvtitle, stl_drvversion); @@ -4706,6 +4522,29 @@ static int __init stallion_module_init(void) spin_lock_init(&stallion_lock); spin_lock_init(&brd_lock); + stl_serial = alloc_tty_driver(STL_MAXBRDS * STL_MAXPORTS); + if (!stl_serial) { + retval = -ENOMEM; + goto err; + } + + 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_frtty; + } + /* * Find any dynamically supported boards. That is via module load * line options. @@ -4722,23 +4561,23 @@ static int __init stallion_module_init(void) brdp->ioaddr2 = conf.ioaddr2; brdp->irq = conf.irq; brdp->irqtype = conf.irqtype; - if (stl_brdinit(brdp)) + stl_brds[brdp->brdnr] = brdp; + if (stl_brdinit(brdp)) { + stl_brds[brdp->brdnr] = NULL; kfree(brdp); - else { - stl_brds[brdp->brdnr] = brdp; + } else { + for (j = 0; j < brdp->nrports; j++) + tty_register_device(stl_serial, + brdp->brdnr * STL_MAXPORTS + j, NULL); 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; + if (retval && stl_nrbrds == 0) { + printk(KERN_ERR "STALLION: can't register pci driver\n"); + goto err_unrtty; } /* @@ -4749,50 +4588,25 @@ static int __init stallion_module_init(void) 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; - } + if (IS_ERR(stallion_class)) + printk("STALLION: failed to create class\n"); 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_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; - } + device_create(stallion_class, NULL, MKDEV(STL_SIOMEMMAJOR, i), + NULL, "staliomem%d", i); 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"); +err_unrtty: + tty_unregister_driver(stl_serial); +err_frtty: 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) { - int i; + struct stlbrd *brdp; + unsigned int i, j; pr_debug("cleanup_module()\n"); @@ -4805,19 +4619,25 @@ static void __exit stallion_module_exit(void) * a hangup on every open port - to try to flush out any processes * hanging onto ports. */ - tty_unregister_driver(stl_serial); - put_tty_driver(stl_serial); + 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); + } for (i = 0; i < 4; i++) - class_device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i)); - if ((i = unregister_chrdev(STL_SIOMEMMAJOR, "staliomem"))) - printk("STALLION: failed to un-register serial memory device, " - "errno=%d\n", -i); + device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i)); + unregister_chrdev(STL_SIOMEMMAJOR, "staliomem"); class_destroy(stallion_class); pci_unregister_driver(&stl_pcidriver); stl_free_isabrds(); + + tty_unregister_driver(stl_serial); + put_tty_driver(stl_serial); } module_init(stallion_module_init);