Merge branch 'urgent' of git://git.kernel.org/pub/scm/linux/kernel/git/brodo/pcmcia-2.6
[safe/jmp/linux-2.6] / drivers / char / istallion.c
index 5c3dc6b..4cd6c52 100644 (file)
 /*****************************************************************************/
 
 #include <linux/module.h>
+#include <linux/sched.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
 #include <linux/serial.h>
+#include <linux/seq_file.h>
 #include <linux/cdk.h>
 #include <linux/comstats.h>
 #include <linux/istallion.h>
@@ -210,7 +213,6 @@ static int          stli_shared;
  *     with the slave. Most of them need to be updated atomically, so always
  *     use the bit setting operations (unless protected by cli/sti).
  */
-#define        ST_INITIALIZING 1
 #define        ST_OPENING      2
 #define        ST_CLOSING      3
 #define        ST_CMDING       4
@@ -613,13 +615,12 @@ static int        stli_breakctl(struct tty_struct *tty, int state);
 static void    stli_waituntilsent(struct tty_struct *tty, int timeout);
 static void    stli_sendxchar(struct tty_struct *tty, char ch);
 static void    stli_hangup(struct tty_struct *tty);
-static int     stli_portinfo(struct stlibrd *brdp, struct stliport *portp, int portnr, char *pos);
 
 static int     stli_brdinit(struct stlibrd *brdp);
 static int     stli_startbrd(struct stlibrd *brdp);
 static ssize_t stli_memread(struct file *fp, char __user *buf, size_t count, loff_t *offp);
 static ssize_t stli_memwrite(struct file *fp, const char __user *buf, size_t count, loff_t *offp);
-static int     stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg);
+static long    stli_memioctl(struct file *fp, unsigned int cmd, unsigned long arg);
 static void    stli_brdpoll(struct stlibrd *brdp, cdkhdr_t __iomem *hdrp);
 static void    stli_poll(unsigned long arg);
 static int     stli_hostcmd(struct stlibrd *brdp, struct stliport *portp);
@@ -702,7 +703,7 @@ static const struct file_operations stli_fsiomem = {
        .owner          = THIS_MODULE,
        .read           = stli_memread,
        .write          = stli_memwrite,
-       .ioctl          = stli_memioctl,
+       .unlocked_ioctl = stli_memioctl,
 };
 
 /*****************************************************************************/
@@ -781,13 +782,32 @@ static int stli_parsebrd(struct stlconf *confp, char **argp)
 
 /*****************************************************************************/
 
+/*
+ *     On the first open of the device setup the port hardware, and
+ *     initialize the per port data structure. Since initializing the port
+ *     requires several commands to the board we will need to wait for any
+ *     other open that is already initializing the port.
+ *
+ *     Locking: protected by the port mutex.
+ */
+
+static int stli_activate(struct tty_port *port, struct tty_struct *tty)
+{
+       struct stliport *portp = container_of(port, struct stliport, port);
+       struct stlibrd *brdp = stli_brds[portp->brdnr];
+       int rc;
+
+       if ((rc = stli_initopen(tty, brdp, portp)) >= 0)
+               clear_bit(TTY_IO_ERROR, &tty->flags);
+       wake_up_interruptible(&portp->raw_wait);
+       return rc;
+}
+
 static int stli_open(struct tty_struct *tty, struct file *filp)
 {
        struct stlibrd *brdp;
        struct stliport *portp;
-       struct tty_port *port;
        unsigned int minordev, brdnr, portnr;
-       int rc;
 
        minordev = tty->index;
        brdnr = MINOR2BRD(minordev);
@@ -807,95 +827,56 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
                return -ENODEV;
        if (portp->devnr < 1)
                return -ENODEV;
-       port = &portp->port;
-
-/*
- *     On the first open of the device setup the port hardware, and
- *     initialize the per port data structure. Since initializing the port
- *     requires several commands to the board we will need to wait for any
- *     other open that is already initializing the port.
- *
- *     Review - locking
- */
-       tty_port_tty_set(port, tty);
-       tty->driver_data = portp;
-       port->count++;
-
-       wait_event_interruptible(portp->raw_wait,
-                       !test_bit(ST_INITIALIZING, &portp->state));
-       if (signal_pending(current))
-               return -ERESTARTSYS;
-
-       if ((portp->port.flags & ASYNC_INITIALIZED) == 0) {
-               set_bit(ST_INITIALIZING, &portp->state);
-               if ((rc = stli_initopen(tty, brdp, portp)) >= 0) {
-                       /* Locking */
-                       port->flags |= ASYNC_INITIALIZED;
-                       clear_bit(TTY_IO_ERROR, &tty->flags);
-               }
-               clear_bit(ST_INITIALIZING, &portp->state);
-               wake_up_interruptible(&portp->raw_wait);
-               if (rc < 0)
-                       return rc;
-       }
-       return tty_port_block_til_ready(&portp->port, tty, filp);
+       return tty_port_open(&portp->port, tty, filp);
 }
 
+
 /*****************************************************************************/
 
-static void stli_close(struct tty_struct *tty, struct file *filp)
+static void stli_shutdown(struct tty_port *port)
 {
        struct stlibrd *brdp;
-       struct stliport *portp;
-       struct tty_port *port;
+       unsigned long ftype;
        unsigned long flags;
+       struct stliport *portp = container_of(port, struct stliport, port);
 
-       portp = tty->driver_data;
-       if (portp == NULL)
+       if (portp->brdnr >= stli_nrbrds)
                return;
-       port = &portp->port;
-
-       if (tty_port_close_start(port, tty, filp) == 0)
+       brdp = stli_brds[portp->brdnr];
+       if (brdp == NULL)
                return;
 
-/*
- *     May want to wait for data to drain before closing. The BUSY flag
- *     keeps track of whether we are still transmitting or not. It is
- *     updated by messages from the slave - indicating when all chars
- *     really have drained.
- */
-       spin_lock_irqsave(&stli_lock, flags);
-       if (tty == stli_txcooktty)
-               stli_flushchars(tty);
-       spin_unlock_irqrestore(&stli_lock, flags);
-
-       /* We end up doing this twice for the moment. This needs looking at
-          eventually. Note we still use portp->closing_wait as a result */
-       if (portp->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-               tty_wait_until_sent(tty, portp->closing_wait);
+       /*
+        *      May want to wait for data to drain before closing. The BUSY
+        *      flag keeps track of whether we are still transmitting or not.
+        *      It is updated by messages from the slave - indicating when all
+        *      chars really have drained.
+        */
 
-       /* FIXME: port locking here needs attending to */
-       port->flags &= ~ASYNC_INITIALIZED;
+       if (!test_bit(ST_CLOSING, &portp->state))
+               stli_rawclose(brdp, portp, 0, 0);
 
-       brdp = stli_brds[portp->brdnr];
-       stli_rawclose(brdp, portp, 0, 0);
-       if (tty->termios->c_cflag & HUPCL) {
-               stli_mkasysigs(&portp->asig, 0, 0);
-               if (test_bit(ST_CMDING, &portp->state))
-                       set_bit(ST_DOSIGS, &portp->state);
-               else
-                       stli_sendcmd(brdp, portp, A_SETSIGNALS, &portp->asig,
-                               sizeof(asysigs_t), 0);
-       }
+       spin_lock_irqsave(&stli_lock, flags);
        clear_bit(ST_TXBUSY, &portp->state);
        clear_bit(ST_RXSTOP, &portp->state);
-       set_bit(TTY_IO_ERROR, &tty->flags);
-       tty_ldisc_flush(tty);
-       set_bit(ST_DOFLUSHRX, &portp->state);
-       stli_flushbuffer(tty);
+       spin_unlock_irqrestore(&stli_lock, flags);
+
+       ftype = FLUSHTX | FLUSHRX;
+       stli_cmdwait(brdp, portp, A_FLUSH, &ftype, sizeof(u32), 0);
+}
 
-       tty_port_close_end(port, tty);
-       tty_port_tty_set(port, NULL);
+static void stli_close(struct tty_struct *tty, struct file *filp)
+{
+       struct stliport *portp = tty->driver_data;
+       unsigned long flags;
+       if (portp == NULL)
+               return;
+       spin_lock_irqsave(&stli_lock, flags);
+       /*      Flush any internal buffering out first */
+       if (tty == stli_txcooktty)
+               stli_flushchars(tty);
+       spin_unlock_irqrestore(&stli_lock, flags);
+       tty_port_close(&portp->port, tty, filp);
 }
 
 /*****************************************************************************/
@@ -1140,14 +1121,14 @@ static int stli_carrier_raised(struct tty_port *port)
        return (portp->sigs & TIOCM_CD) ? 1 : 0;
 }
 
-static void stli_raise_dtr_rts(struct tty_port *port)
+static void stli_dtr_rts(struct tty_port *port, int on)
 {
        struct stliport *portp = container_of(port, struct stliport, port);
        struct stlibrd *brdp = stli_brds[portp->brdnr];
-       stli_mkasysigs(&portp->asig, 1, 1);
+       stli_mkasysigs(&portp->asig, on, on);
        if (stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig,
                sizeof(asysigs_t), 0) < 0)
-                       printk(KERN_WARNING "istallion: dtr raise failed.\n");
+                       printk(KERN_WARNING "istallion: dtr set failed.\n");
 }
 
 
@@ -1722,6 +1703,7 @@ static void stli_start(struct tty_struct *tty)
 
 /*****************************************************************************/
 
+
 /*
  *     Hangup this port. This is pretty much like closing the port, only
  *     a little more brutal. No waiting for data to drain. Shutdown the
@@ -1731,47 +1713,8 @@ static void stli_start(struct tty_struct *tty)
 
 static void stli_hangup(struct tty_struct *tty)
 {
-       struct stliport *portp;
-       struct stlibrd *brdp;
-       struct tty_port *port;
-       unsigned long flags;
-
-       portp = tty->driver_data;
-       if (portp == NULL)
-               return;
-       if (portp->brdnr >= stli_nrbrds)
-               return;
-       brdp = stli_brds[portp->brdnr];
-       if (brdp == NULL)
-               return;
-       port = &portp->port;
-
-       spin_lock_irqsave(&port->lock, flags);
-       port->flags &= ~ASYNC_INITIALIZED;
-       spin_unlock_irqrestore(&port->lock, flags);
-
-       if (!test_bit(ST_CLOSING, &portp->state))
-               stli_rawclose(brdp, portp, 0, 0);
-
-       spin_lock_irqsave(&stli_lock, flags);
-       if (tty->termios->c_cflag & HUPCL) {
-               stli_mkasysigs(&portp->asig, 0, 0);
-               if (test_bit(ST_CMDING, &portp->state)) {
-                       set_bit(ST_DOSIGS, &portp->state);
-                       set_bit(ST_DOFLUSHTX, &portp->state);
-                       set_bit(ST_DOFLUSHRX, &portp->state);
-               } else {
-                       stli_sendcmd(brdp, portp, A_SETSIGNALSF,
-                               &portp->asig, sizeof(asysigs_t), 0);
-               }
-       }
-
-       clear_bit(ST_TXBUSY, &portp->state);
-       clear_bit(ST_RXSTOP, &portp->state);
-       set_bit(TTY_IO_ERROR, &tty->flags);
-       spin_unlock_irqrestore(&stli_lock, flags);
-
-       tty_port_hangup(port);
+       struct stliport *portp = tty->driver_data;
+       tty_port_hangup(&portp->port);
 }
 
 /*****************************************************************************/
@@ -1893,20 +1836,10 @@ static void stli_sendxchar(struct tty_struct *tty, char ch)
        stli_cmdwait(brdp, portp, A_PORTCTRL, &actrl, sizeof(asyctrl_t), 0);
 }
 
-/*****************************************************************************/
-
-#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 stli_portinfo(struct stlibrd *brdp, struct stliport *portp, int portnr, char *pos)
+static void stli_portinfo(struct seq_file *m, struct stlibrd *brdp, struct stliport *portp, int portnr)
 {
-       char *sp, *uart;
-       int rc, cnt;
+       char *uart;
+       int rc;
 
        rc = stli_portcmdstats(NULL, portp);
 
@@ -1918,44 +1851,50 @@ static int stli_portinfo(struct stlibrd *brdp, struct stliport *portp, int portn
                default:uart = "CD1400"; break;
                }
        }
-
-       sp = pos;
-       sp += sprintf(sp, "%d: uart:%s ", portnr, uart);
+       seq_printf(m, "%d: uart:%s ", portnr, uart);
 
        if ((brdp->state & BST_STARTED) && (rc >= 0)) {
-               sp += sprintf(sp, "tx:%d rx:%d", (int) stli_comstats.txtotal,
+               char sep;
+
+               seq_printf(m, "tx:%d rx:%d", (int) stli_comstats.txtotal,
                        (int) stli_comstats.rxtotal);
 
                if (stli_comstats.rxframing)
-                       sp += sprintf(sp, " fe:%d",
+                       seq_printf(m, " fe:%d",
                                (int) stli_comstats.rxframing);
                if (stli_comstats.rxparity)
-                       sp += sprintf(sp, " pe:%d",
+                       seq_printf(m, " pe:%d",
                                (int) stli_comstats.rxparity);
                if (stli_comstats.rxbreaks)
-                       sp += sprintf(sp, " brk:%d",
+                       seq_printf(m, " brk:%d",
                                (int) stli_comstats.rxbreaks);
                if (stli_comstats.rxoverrun)
-                       sp += sprintf(sp, " oe:%d",
+                       seq_printf(m, " oe:%d",
                                (int) stli_comstats.rxoverrun);
 
-               cnt = sprintf(sp, "%s%s%s%s%s ",
-                       (stli_comstats.signals & TIOCM_RTS) ? "|RTS" : "",
-                       (stli_comstats.signals & TIOCM_CTS) ? "|CTS" : "",
-                       (stli_comstats.signals & TIOCM_DTR) ? "|DTR" : "",
-                       (stli_comstats.signals & TIOCM_CD) ? "|DCD" : "",
-                       (stli_comstats.signals & TIOCM_DSR) ? "|DSR" : "");
-               *sp = ' ';
-               sp += cnt;
+               sep = ' ';
+               if (stli_comstats.signals & TIOCM_RTS) {
+                       seq_printf(m, "%c%s", sep, "RTS");
+                       sep = '|';
+               }
+               if (stli_comstats.signals & TIOCM_CTS) {
+                       seq_printf(m, "%c%s", sep, "CTS");
+                       sep = '|';
+               }
+               if (stli_comstats.signals & TIOCM_DTR) {
+                       seq_printf(m, "%c%s", sep, "DTR");
+                       sep = '|';
+               }
+               if (stli_comstats.signals & TIOCM_CD) {
+                       seq_printf(m, "%c%s", sep, "DCD");
+                       sep = '|';
+               }
+               if (stli_comstats.signals & TIOCM_DSR) {
+                       seq_printf(m, "%c%s", sep, "DSR");
+                       sep = '|';
+               }
        }
-
-       for (cnt = (sp - pos); (cnt < (MAXLINE - 1)); cnt++)
-               *sp++ = ' ';
-       if (cnt >= MAXLINE)
-               pos[(MAXLINE - 2)] = '+';
-       pos[(MAXLINE - 1)] = '\n';
-
-       return(MAXLINE);
+       seq_putc(m, '\n');
 }
 
 /*****************************************************************************/
@@ -1964,26 +1903,15 @@ static int stli_portinfo(struct stlibrd *brdp, struct stliport *portp, int portn
  *     Port info, read from the /proc file system.
  */
 
-static int stli_readproc(char *page, char **start, off_t off, int count, int *eof, void *data)
+static int stli_proc_show(struct seq_file *m, void *v)
 {
        struct stlibrd *brdp;
        struct stliport *portp;
        unsigned int brdnr, portnr, totalport;
-       int curoff, maxoff;
-       char *pos;
 
-       pos = page;
        totalport = 0;
-       curoff = 0;
-
-       if (off == 0) {
-               pos += sprintf(pos, "%s: version %s", stli_drvtitle,
-                       stli_drvversion);
-               while (pos < (page + MAXLINE - 1))
-                       *pos++ = ' ';
-               *pos++ = '\n';
-       }
-       curoff =  MAXLINE;
+
+       seq_printf(m, "%s: version %s\n", stli_drvtitle, stli_drvversion);
 
 /*
  *     We scan through for each board, panel and port. The offset is
@@ -1996,33 +1924,31 @@ static int stli_readproc(char *page, char **start, off_t off, int count, int *eo
                if (brdp->state == 0)
                        continue;
 
-               maxoff = curoff + (brdp->nrports * MAXLINE);
-               if (off >= maxoff) {
-                       curoff = maxoff;
-                       continue;
-               }
-
                totalport = brdnr * STL_MAXPORTS;
                for (portnr = 0; (portnr < brdp->nrports); portnr++,
                    totalport++) {
                        portp = brdp->ports[portnr];
                        if (portp == NULL)
                                continue;
-                       if (off >= (curoff += MAXLINE))
-                               continue;
-                       if ((pos - page + MAXLINE) > count)
-                               goto stli_readdone;
-                       pos += stli_portinfo(brdp, portp, totalport, pos);
+                       stli_portinfo(m, brdp, portp, totalport);
                }
        }
+       return 0;
+}
 
-       *eof = 1;
-
-stli_readdone:
-       *start = page;
-       return(pos - page);
+static int stli_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, stli_proc_show, NULL);
 }
 
+static const struct file_operations stli_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = stli_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 /*****************************************************************************/
 
 /*
@@ -3802,7 +3728,7 @@ err:
        return retval;
 }
 
-static void stli_pciremove(struct pci_dev *pdev)
+static void __devexit stli_pciremove(struct pci_dev *pdev)
 {
        struct stlibrd *brdp = pci_get_drvdata(pdev);
 
@@ -4326,7 +4252,7 @@ static int stli_getbrdstruct(struct stlibrd __user *arg)
  *     reset it, and start/stop it.
  */
 
-static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg)
+static long stli_memioctl(struct file *fp, unsigned int cmd, unsigned long arg)
 {
        struct stlibrd *brdp;
        int brdnr, rc, done;
@@ -4371,7 +4297,7 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un
  *     Now handle the board specific ioctls. These all depend on the
  *     minor number of the device they were called from.
  */
-       brdnr = iminor(ip);
+       brdnr = iminor(fp->f_dentry->d_inode);
        if (brdnr >= STL_MAXBRDS)
                return -ENODEV;
        brdp = stli_brds[brdnr];
@@ -4427,14 +4353,16 @@ static const struct tty_operations stli_ops = {
        .break_ctl = stli_breakctl,
        .wait_until_sent = stli_waituntilsent,
        .send_xchar = stli_sendxchar,
-       .read_proc = stli_readproc,
        .tiocmget = stli_tiocmget,
        .tiocmset = stli_tiocmset,
+       .proc_fops = &stli_proc_fops,
 };
 
 static const struct tty_port_operations stli_port_ops = {
        .carrier_raised = stli_carrier_raised,
-       .raise_dtr_rts = stli_raise_dtr_rts,
+       .dtr_rts = stli_dtr_rts,
+       .activate = stli_activate,
+       .shutdown = stli_shutdown,
 };
 
 /*****************************************************************************/