USB: usbmon: fix bug in mon_buff_area_shrink
[safe/jmp/linux-2.6] / drivers / char / moxa.c
index dd10f14..dd0083b 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
 #include <linux/major.h>
+#include <linux/smp_lock.h>
 #include <linux/string.h>
 #include <linux/fcntl.h>
 #include <linux/ptrace.h>
@@ -135,7 +136,6 @@ struct moxa_port {
        void __iomem *tableAddr;
 
        int type;
-       int close_delay;
        int cflag;
        unsigned long statusflags;
 
@@ -206,7 +206,8 @@ static int moxa_tiocmset(struct tty_struct *tty, struct file *file,
 static void moxa_poll(unsigned long);
 static void moxa_set_tty_param(struct tty_struct *, struct ktermios *);
 static void moxa_setup_empty_event(struct tty_struct *);
-static void moxa_shut_down(struct moxa_port *);
+static void moxa_shut_down(struct tty_struct *);
+static int moxa_carrier_raised(struct tty_port *);
 /*
  * moxa board interface functions:
  */
@@ -218,7 +219,7 @@ static void MoxaPortLineCtrl(struct moxa_port *, int, int);
 static void MoxaPortFlowCtrl(struct moxa_port *, int, int, int, int, int);
 static int MoxaPortLineStatus(struct moxa_port *);
 static void MoxaPortFlushData(struct moxa_port *, int);
-static int MoxaPortWriteData(struct moxa_port *, const unsigned char *, int);
+static int MoxaPortWriteData(struct tty_struct *, const unsigned char *, int);
 static int MoxaPortReadData(struct moxa_port *);
 static int MoxaPortTxQueue(struct moxa_port *);
 static int MoxaPortRxQueue(struct moxa_port *);
@@ -333,6 +334,7 @@ static int moxa_ioctl(struct tty_struct *tty, struct file *file,
                for (i = 0; i < MAX_BOARDS; i++) {
                        p = moxa_boards[i].ports;
                        for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) {
+                               struct tty_struct *ttyp;
                                memset(&tmp, 0, sizeof(tmp));
                                if (!moxa_boards[i].ready)
                                        goto copy;
@@ -345,10 +347,12 @@ static int moxa_ioctl(struct tty_struct *tty, struct file *file,
                                if (status & 4)
                                        tmp.dcd = 1;
 
-                               if (!p->port.tty || !p->port.tty->termios)
+                               ttyp = tty_port_tty_get(&p->port);
+                               if (!ttyp || !ttyp->termios)
                                        tmp.cflag = p->cflag;
                                else
-                                       tmp.cflag = p->port.tty->termios->c_cflag;
+                                       tmp.cflag = ttyp->termios->c_cflag;
+                               tty_kref_put(tty);
 copy:
                                if (copy_to_user(argm, &tmp, sizeof(tmp))) {
                                        mutex_unlock(&moxa_openlock);
@@ -375,12 +379,13 @@ copy:
        return ret;
 }
 
-static void moxa_break_ctl(struct tty_struct *tty, int state)
+static int moxa_break_ctl(struct tty_struct *tty, int state)
 {
        struct moxa_port *port = tty->driver_data;
 
        moxafunc(port->tableAddr, state ? FC_SendBreak : FC_StopBreak,
                        Magic_code);
+       return 0;
 }
 
 static const struct tty_operations moxa_ops = {
@@ -402,6 +407,10 @@ static const struct tty_operations moxa_ops = {
        .tiocmset = moxa_tiocmset,
 };
 
+static const struct tty_port_operations moxa_port_ops = {
+       .carrier_raised = moxa_carrier_raised,
+};
+
 static struct tty_driver *moxaDriver;
 static DEFINE_TIMER(moxaTimer, moxa_poll, 0, 0);
 static DEFINE_SPINLOCK(moxa_lock);
@@ -510,7 +519,7 @@ static int moxa_real_load_code(struct moxa_board_conf *brd, const void *ptr,
                size_t len)
 {
        void __iomem *baseAddr = brd->basemem;
-       const u16 *uptr = ptr;
+       const __le16 *uptr = ptr;
        size_t wlen, len2, j;
        unsigned long key, loadbuf, loadlen, checksum, checksum_ok;
        unsigned int i, retry;
@@ -822,10 +831,10 @@ static int moxa_init_board(struct moxa_board_conf *brd, struct device *dev)
        }
 
        for (i = 0, p = brd->ports; i < MAX_PORTS_PER_BOARD; i++, p++) {
+               tty_port_init(&p->port);
+               p->port.ops = &moxa_port_ops;
                p->type = PORT_16550A;
-               p->close_delay = 5 * HZ / 10;
                p->cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
-               tty_port_init(&p->port);
        }
 
        switch (brd->boardType) {
@@ -881,8 +890,14 @@ static void moxa_board_deinit(struct moxa_board_conf *brd)
 
        /* pci hot-un-plug support */
        for (a = 0; a < brd->numPorts; a++)
-               if (brd->ports[a].port.flags & ASYNC_INITIALIZED)
-                       tty_hangup(brd->ports[a].port.tty);
+               if (brd->ports[a].port.flags & ASYNC_INITIALIZED) {
+                       struct tty_struct *tty = tty_port_tty_get(
+                                               &brd->ports[a].port);
+                       if (tty) {
+                               tty_hangup(tty);
+                               tty_kref_put(tty);
+                       }
+               }
        while (1) {
                opened = 0;
                for (a = 0; a < brd->numPorts; a++)
@@ -1097,24 +1112,37 @@ static void __exit moxa_exit(void)
 module_init(moxa_init);
 module_exit(moxa_exit);
 
-static void moxa_close_port(struct moxa_port *ch)
+static void moxa_close_port(struct tty_struct *tty)
 {
-       moxa_shut_down(ch);
+       struct moxa_port *ch = tty->driver_data;
+       moxa_shut_down(tty);
        MoxaPortFlushData(ch, 2);
        ch->port.flags &= ~ASYNC_NORMAL_ACTIVE;
-       ch->port.tty->driver_data = NULL;
-       ch->port.tty = NULL;
+       tty->driver_data = NULL;
+       tty_port_tty_set(&ch->port, NULL);
+}
+
+static int moxa_carrier_raised(struct tty_port *port)
+{
+       struct moxa_port *ch = container_of(port, struct moxa_port, port);
+       int dcd;
+
+       spin_lock_bh(&moxa_lock);
+       dcd = ch->DCDState;
+       spin_unlock_bh(&moxa_lock);
+       return dcd;
 }
 
 static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp,
                            struct moxa_port *ch)
 {
+       struct tty_port *port = &ch->port;
        DEFINE_WAIT(wait);
        int retval = 0;
        u8 dcd;
 
        while (1) {
-               prepare_to_wait(&ch->port.open_wait, &wait, TASK_INTERRUPTIBLE);
+               prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE);
                if (tty_hung_up_p(filp)) {
 #ifdef SERIAL_DO_RESTART
                        retval = -ERESTARTSYS;
@@ -1123,9 +1151,7 @@ static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp,
 #endif
                        break;
                }
-               spin_lock_bh(&moxa_lock);
-               dcd = ch->DCDState;
-               spin_unlock_bh(&moxa_lock);
+               dcd = tty_port_carrier_raised(port);
                if (dcd)
                        break;
 
@@ -1135,7 +1161,7 @@ static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp,
                }
                schedule();
        }
-       finish_wait(&ch->port.open_wait, &wait);
+       finish_wait(&port->open_wait, &wait);
 
        return retval;
 }
@@ -1159,10 +1185,15 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
                return -ENODEV;
        }
 
+       if (port % MAX_PORTS_PER_BOARD >= brd->numPorts) {
+               mutex_unlock(&moxa_openlock);
+               return -ENODEV;
+       }
+
        ch = &brd->ports[port % MAX_PORTS_PER_BOARD];
        ch->port.count++;
        tty->driver_data = ch;
-       ch->port.tty = tty;
+       tty_port_tty_set(&ch->port, tty);
        if (!(ch->port.flags & ASYNC_INITIALIZED)) {
                ch->statusflags = 0;
                moxa_set_tty_param(tty, tty->termios);
@@ -1180,7 +1211,7 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
        if (retval) {
                if (ch->port.count) /* 0 means already hung up... */
                        if (--ch->port.count == 0)
-                               moxa_close_port(ch);
+                               moxa_close_port(tty);
        } else
                ch->port.flags |= ASYNC_NORMAL_ACTIVE;
        mutex_unlock(&moxa_openlock);
@@ -1220,7 +1251,7 @@ static void moxa_close(struct tty_struct *tty, struct file *filp)
                tty_wait_until_sent(tty, 30 * HZ);      /* 30 seconds timeout */
        }
 
-       moxa_close_port(ch);
+       moxa_close_port(tty);
 unlock:
        mutex_unlock(&moxa_openlock);
 }
@@ -1235,7 +1266,7 @@ static int moxa_write(struct tty_struct *tty,
                return 0;
 
        spin_lock_bh(&moxa_lock);
-       len = MoxaPortWriteData(ch, buf, count);
+       len = MoxaPortWriteData(tty, buf, count);
        spin_unlock_bh(&moxa_lock);
 
        ch->statusflags |= LOWWAIT;
@@ -1410,7 +1441,7 @@ static void moxa_hangup(struct tty_struct *tty)
                return;
        }
        ch->port.count = 0;
-       moxa_close_port(ch);
+       moxa_close_port(tty);
        mutex_unlock(&moxa_openlock);
 
        wake_up_interruptible(&ch->port.open_wait);
@@ -1418,11 +1449,14 @@ static void moxa_hangup(struct tty_struct *tty)
 
 static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd)
 {
+       struct tty_struct *tty;
        dcd = !!dcd;
 
-       if (dcd != p->DCDState && p->port.tty && C_CLOCAL(p->port.tty)) {
-               if (!dcd)
-                       tty_hangup(p->port.tty);
+       if (dcd != p->DCDState) {
+               tty = tty_port_tty_get(&p->port);
+               if (tty && C_CLOCAL(tty) && !dcd)
+                       tty_hangup(tty);
+               tty_kref_put(tty);
        }
        p->DCDState = dcd;
 }
@@ -1430,7 +1464,7 @@ static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd)
 static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
                u16 __iomem *ip)
 {
-       struct tty_struct *tty = p->port.tty;
+       struct tty_struct *tty = tty_port_tty_get(&p->port);
        void __iomem *ofsAddr;
        unsigned int inited = p->port.flags & ASYNC_INITIALIZED;
        u16 intr;
@@ -1458,11 +1492,11 @@ static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
        }
 
        if (!handle) /* nothing else to do */
-               return 0;
+               goto put;
 
        intr = readw(ip); /* port irq status */
        if (intr == 0)
-               return 0;
+               goto put;
 
        writew(0, ip); /* ACK port */
        ofsAddr = p->tableAddr;
@@ -1471,7 +1505,7 @@ static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
                                ofsAddr + HostStat);
 
        if (!inited)
-               return 0;
+               goto put;
 
        if (tty && (intr & IntrBreak) && !I_IGNBRK(tty)) { /* BREAK */
                tty_insert_flip_char(tty, 0, TTY_BREAK);
@@ -1480,6 +1514,8 @@ static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
 
        if (intr & IntrLine)
                moxa_new_dcdstate(p, readb(ofsAddr + FlagStat) & DCD_state);
+put:
+       tty_kref_put(tty);
 
        return 0;
 }
@@ -1561,9 +1597,9 @@ static void moxa_setup_empty_event(struct tty_struct *tty)
        spin_unlock_bh(&moxa_lock);
 }
 
-static void moxa_shut_down(struct moxa_port *ch)
+static void moxa_shut_down(struct tty_struct *tty)
 {
-       struct tty_struct *tp = ch->port.tty;
+       struct moxa_port *ch = tty->driver_data;
 
        if (!(ch->port.flags & ASYNC_INITIALIZED))
                return;
@@ -1573,7 +1609,7 @@ static void moxa_shut_down(struct moxa_port *ch)
        /*
         * If we're a modem control device and HUPCL is on, drop RTS & DTR.
         */
-       if (C_HUPCL(tp))
+       if (C_HUPCL(tty))
                MoxaPortLineCtrl(ch, 0, 0);
 
        spin_lock_bh(&moxa_lock);
@@ -1954,9 +1990,10 @@ static int MoxaPortLineStatus(struct moxa_port *port)
        return val;
 }
 
-static int MoxaPortWriteData(struct moxa_port *port,
+static int MoxaPortWriteData(struct tty_struct *tty,
                const unsigned char *buffer, int len)
 {
+       struct moxa_port *port = tty->driver_data;
        void __iomem *baseAddr, *ofsAddr, *ofs;
        unsigned int c, total;
        u16 head, tail, tx_mask, spage, epage;
@@ -2124,7 +2161,7 @@ static int moxa_get_serial_info(struct moxa_port *info,
                .line = info->port.tty->index,
                .flags = info->port.flags,
                .baud_base = 921600,
-               .close_delay = info->close_delay
+               .close_delay = info->port.close_delay
        };
        return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
 }
@@ -2148,7 +2185,7 @@ static int moxa_set_serial_info(struct moxa_port *info,
                     (info->port.flags & ~ASYNC_USR_MASK)))
                        return -EPERM;
        } else
-               info->close_delay = new_serial.close_delay * HZ / 100;
+               info->port.close_delay = new_serial.close_delay * HZ / 100;
 
        new_serial.flags = (new_serial.flags & ~ASYNC_FLAGS);
        new_serial.flags |= (info->port.flags & ASYNC_FLAGS);