Merge git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/v4l-dvb
[pandora-kernel.git] / drivers / char / moxa.c
index 318c465..2bba250 100644 (file)
@@ -2,7 +2,8 @@
 /*
  *           moxa.c  -- MOXA Intellio family multiport serial driver.
  *
- *      Copyright (C) 1999-2000  Moxa Technologies (support@moxa.com.tw).
+ *      Copyright (C) 1999-2000  Moxa Technologies (support@moxa.com).
+ *      Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com>
  *
  *      This code is loosely based on the Linux serial driver, written by
  *      Linus Torvalds, Theodore T'so and others.
@@ -49,7 +50,7 @@
 
 #include "moxa.h"
 
-#define MOXA_VERSION           "5.1k"
+#define MOXA_VERSION           "6.0k"
 
 #define MOXA_FW_HDRLEN         32
 
@@ -129,17 +130,13 @@ struct moxaq_str {
 };
 
 struct moxa_port {
+       struct tty_port port;
        struct moxa_board_conf *board;
-       struct tty_struct *tty;
        void __iomem *tableAddr;
 
        int type;
-       int close_delay;
-       unsigned int count;
-       int asyncflags;
        int cflag;
        unsigned long statusflags;
-       wait_queue_head_t open_wait;
 
        u8 DCDState;
        u8 lineCtrl;
@@ -347,10 +344,10 @@ static int moxa_ioctl(struct tty_struct *tty, struct file *file,
                                if (status & 4)
                                        tmp.dcd = 1;
 
-                               if (!p->tty || !p->tty->termios)
+                               if (!p->port.tty || !p->port.tty->termios)
                                        tmp.cflag = p->cflag;
                                else
-                                       tmp.cflag = p->tty->termios->c_cflag;
+                                       tmp.cflag = p->port.tty->termios->c_cflag;
 copy:
                                if (copy_to_user(argm, &tmp, sizeof(tmp))) {
                                        mutex_unlock(&moxa_openlock);
@@ -720,7 +717,7 @@ static int moxa_load_code(struct moxa_board_conf *brd, const void *ptr,
 
 static int moxa_load_fw(struct moxa_board_conf *brd, const struct firmware *fw)
 {
-       void *ptr = fw->data;
+       const void *ptr = fw->data;
        char rsn[64];
        u16 lens[5];
        size_t len;
@@ -733,7 +730,7 @@ static int moxa_load_fw(struct moxa_board_conf *brd, const struct firmware *fw)
                u8 model;       /* C218T=1, C320T=2, CP204=3 */
                u8 reserved2[8];
                __le16 len[5];
-       } *hdr = ptr;
+       } const *hdr = ptr;
 
        BUILD_BUG_ON(ARRAY_SIZE(hdr->len) != ARRAY_SIZE(lens));
 
@@ -824,10 +821,9 @@ 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->type = PORT_16550A;
-               p->close_delay = 5 * HZ / 10;
                p->cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
-               init_waitqueue_head(&p->open_wait);
        }
 
        switch (brd->boardType) {
@@ -845,7 +841,10 @@ static int moxa_init_board(struct moxa_board_conf *brd, struct device *dev)
 
        ret = request_firmware(&fw, file, dev);
        if (ret) {
-               printk(KERN_ERR "request_firmware failed\n");
+               printk(KERN_ERR "MOXA: request_firmware failed. Make sure "
+                               "you've placed '%s' file into your firmware "
+                               "loader directory (e.g. /lib/firmware)\n",
+                               file);
                goto err_free;
        }
 
@@ -880,12 +879,12 @@ 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].asyncflags & ASYNC_INITIALIZED)
-                       tty_hangup(brd->ports[a].tty);
+               if (brd->ports[a].port.flags & ASYNC_INITIALIZED)
+                       tty_hangup(brd->ports[a].port.tty);
        while (1) {
                opened = 0;
                for (a = 0; a < brd->numPorts; a++)
-                       if (brd->ports[a].asyncflags & ASYNC_INITIALIZED)
+                       if (brd->ports[a].port.flags & ASYNC_INITIALIZED)
                                opened++;
                mutex_unlock(&moxa_openlock);
                if (!opened)
@@ -933,7 +932,7 @@ static int __devinit moxa_pci_probe(struct pci_dev *pdev,
                goto err;
        }
 
-       board->basemem = ioremap(pci_resource_start(pdev, 2), 0x4000);
+       board->basemem = ioremap_nocache(pci_resource_start(pdev, 2), 0x4000);
        if (board->basemem == NULL) {
                dev_err(&pdev->dev, "can't remap io space 2\n");
                goto err_reg;
@@ -961,6 +960,9 @@ static int __devinit moxa_pci_probe(struct pci_dev *pdev,
 
        pci_set_drvdata(pdev, board);
 
+       dev_info(&pdev->dev, "board '%s' ready (%u ports, firmware loaded)\n",
+                       moxa_brdname[board_type - 1], board->numPorts);
+
        return 0;
 err_base:
        iounmap(board->basemem);
@@ -1035,7 +1037,7 @@ static int __init moxa_init(void)
                        brd->numPorts = type[i] == MOXA_BOARD_C218_ISA ? 8 :
                                        numports[i];
                        brd->busType = MOXA_BUS_TYPE_ISA;
-                       brd->basemem = ioremap(baseaddr[i], 0x4000);
+                       brd->basemem = ioremap_nocache(baseaddr[i], 0x4000);
                        if (!brd->basemem) {
                                printk(KERN_ERR "MOXA: can't remap %lx\n",
                                                baseaddr[i]);
@@ -1047,6 +1049,10 @@ static int __init moxa_init(void)
                                continue;
                        }
 
+                       printk(KERN_INFO "MOXA isa board found at 0x%.8lu and "
+                                       "ready (%u ports, firmware loaded)\n",
+                                       baseaddr[i], brd->numPorts);
+
                        brd++;
                        isabrds++;
                }
@@ -1093,9 +1099,9 @@ static void moxa_close_port(struct moxa_port *ch)
 {
        moxa_shut_down(ch);
        MoxaPortFlushData(ch, 2);
-       ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE;
-       ch->tty->driver_data = NULL;
-       ch->tty = NULL;
+       ch->port.flags &= ~ASYNC_NORMAL_ACTIVE;
+       ch->port.tty->driver_data = NULL;
+       ch->port.tty = NULL;
 }
 
 static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp,
@@ -1106,7 +1112,7 @@ static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp,
        u8 dcd;
 
        while (1) {
-               prepare_to_wait(&ch->open_wait, &wait, TASK_INTERRUPTIBLE);
+               prepare_to_wait(&ch->port.open_wait, &wait, TASK_INTERRUPTIBLE);
                if (tty_hung_up_p(filp)) {
 #ifdef SERIAL_DO_RESTART
                        retval = -ERESTARTSYS;
@@ -1127,7 +1133,7 @@ static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp,
                }
                schedule();
        }
-       finish_wait(&ch->open_wait, &wait);
+       finish_wait(&ch->port.open_wait, &wait);
 
        return retval;
 }
@@ -1152,16 +1158,16 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
        }
 
        ch = &brd->ports[port % MAX_PORTS_PER_BOARD];
-       ch->count++;
+       ch->port.count++;
        tty->driver_data = ch;
-       ch->tty = tty;
-       if (!(ch->asyncflags & ASYNC_INITIALIZED)) {
+       ch->port.tty = tty;
+       if (!(ch->port.flags & ASYNC_INITIALIZED)) {
                ch->statusflags = 0;
                moxa_set_tty_param(tty, tty->termios);
                MoxaPortLineCtrl(ch, 1, 1);
                MoxaPortEnable(ch);
                MoxaSetFifo(ch, ch->type == PORT_16550A);
-               ch->asyncflags |= ASYNC_INITIALIZED;
+               ch->port.flags |= ASYNC_INITIALIZED;
        }
        mutex_unlock(&moxa_openlock);
 
@@ -1170,11 +1176,11 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
                retval = moxa_block_till_ready(tty, filp, ch);
        mutex_lock(&moxa_openlock);
        if (retval) {
-               if (ch->count) /* 0 means already hung up... */
-                       if (--ch->count == 0)
+               if (ch->port.count) /* 0 means already hung up... */
+                       if (--ch->port.count == 0)
                                moxa_close_port(ch);
        } else
-               ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
+               ch->port.flags |= ASYNC_NORMAL_ACTIVE;
        mutex_unlock(&moxa_openlock);
 
        return retval;
@@ -1193,21 +1199,21 @@ static void moxa_close(struct tty_struct *tty, struct file *filp)
        ch = tty->driver_data;
        if (ch == NULL)
                goto unlock;
-       if (tty->count == 1 && ch->count != 1) {
+       if (tty->count == 1 && ch->port.count != 1) {
                printk(KERN_WARNING "moxa_close: bad serial port count; "
-                       "tty->count is 1, ch->count is %d\n", ch->count);
-               ch->count = 1;
+                       "tty->count is 1, ch->port.count is %d\n", ch->port.count);
+               ch->port.count = 1;
        }
-       if (--ch->count < 0) {
+       if (--ch->port.count < 0) {
                printk(KERN_WARNING "moxa_close: bad serial port count, "
                        "device=%s\n", tty->name);
-               ch->count = 0;
+               ch->port.count = 0;
        }
-       if (ch->count)
+       if (ch->port.count)
                goto unlock;
 
        ch->cflag = tty->termios->c_cflag;
-       if (ch->asyncflags & ASYNC_INITIALIZED) {
+       if (ch->port.flags & ASYNC_INITIALIZED) {
                moxa_setup_empty_event(tty);
                tty_wait_until_sent(tty, 30 * HZ);      /* 30 seconds timeout */
        }
@@ -1269,6 +1275,7 @@ static int moxa_chars_in_buffer(struct tty_struct *tty)
         */
        if (ch == NULL)
                return 0;
+       lock_kernel();
        chars = MoxaPortTxQueue(ch);
        if (chars) {
                /*
@@ -1278,6 +1285,7 @@ static int moxa_chars_in_buffer(struct tty_struct *tty)
                if (!(ch->statusflags & EMPTYWAIT))
                        moxa_setup_empty_event(tty);
        }
+       unlock_kernel();
        return chars;
 }
 
@@ -1361,7 +1369,7 @@ static void moxa_set_termios(struct tty_struct *tty,
                return;
        moxa_set_tty_param(tty, old_termios);
        if (!(old_termios->c_cflag & CLOCAL) && C_CLOCAL(tty))
-               wake_up_interruptible(&ch->open_wait);
+               wake_up_interruptible(&ch->port.open_wait);
 }
 
 static void moxa_stop(struct tty_struct *tty)
@@ -1399,20 +1407,20 @@ static void moxa_hangup(struct tty_struct *tty)
                mutex_unlock(&moxa_openlock);
                return;
        }
-       ch->count = 0;
+       ch->port.count = 0;
        moxa_close_port(ch);
        mutex_unlock(&moxa_openlock);
 
-       wake_up_interruptible(&ch->open_wait);
+       wake_up_interruptible(&ch->port.open_wait);
 }
 
 static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd)
 {
        dcd = !!dcd;
 
-       if (dcd != p->DCDState && p->tty && C_CLOCAL(p->tty)) {
+       if (dcd != p->DCDState && p->port.tty && C_CLOCAL(p->port.tty)) {
                if (!dcd)
-                       tty_hangup(p->tty);
+                       tty_hangup(p->port.tty);
        }
        p->DCDState = dcd;
 }
@@ -1420,9 +1428,9 @@ 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->tty;
+       struct tty_struct *tty = p->port.tty;
        void __iomem *ofsAddr;
-       unsigned int inited = p->asyncflags & ASYNC_INITIALIZED;
+       unsigned int inited = p->port.flags & ASYNC_INITIALIZED;
        u16 intr;
 
        if (tty) {
@@ -1553,9 +1561,9 @@ static void moxa_setup_empty_event(struct tty_struct *tty)
 
 static void moxa_shut_down(struct moxa_port *ch)
 {
-       struct tty_struct *tp = ch->tty;
+       struct tty_struct *tp = ch->port.tty;
 
-       if (!(ch->asyncflags & ASYNC_INITIALIZED))
+       if (!(ch->port.flags & ASYNC_INITIALIZED))
                return;
 
        MoxaPortDisable(ch);
@@ -1567,7 +1575,7 @@ static void moxa_shut_down(struct moxa_port *ch)
                MoxaPortLineCtrl(ch, 0, 0);
 
        spin_lock_bh(&moxa_lock);
-       ch->asyncflags &= ~ASYNC_INITIALIZED;
+       ch->port.flags &= ~ASYNC_INITIALIZED;
        spin_unlock_bh(&moxa_lock);
 }
 
@@ -1962,7 +1970,7 @@ static int MoxaPortWriteData(struct moxa_port *port,
        c = (head > tail) ? (head - tail - 1) : (head - tail + tx_mask);
        if (c > len)
                c = len;
-       moxaLog.txcnt[port->tty->index] += c;
+       moxaLog.txcnt[port->port.tty->index] += c;
        total = c;
        if (spage == epage) {
                bufhead = readw(ofsAddr + Ofs_txb);
@@ -2004,7 +2012,7 @@ static int MoxaPortWriteData(struct moxa_port *port,
 
 static int MoxaPortReadData(struct moxa_port *port)
 {
-       struct tty_struct *tty = port->tty;
+       struct tty_struct *tty = port->port.tty;
        unsigned char *dst;
        void __iomem *baseAddr, *ofsAddr, *ofs;
        unsigned int count, len, total;
@@ -2111,10 +2119,10 @@ static int moxa_get_serial_info(struct moxa_port *info,
 {
        struct serial_struct tmp = {
                .type = info->type,
-               .line = info->tty->index,
-               .flags = info->asyncflags,
+               .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;
 }
@@ -2135,13 +2143,13 @@ static int moxa_set_serial_info(struct moxa_port *info,
 
        if (!capable(CAP_SYS_ADMIN)) {
                if (((new_serial.flags & ~ASYNC_USR_MASK) !=
-                    (info->asyncflags & ~ASYNC_USR_MASK)))
+                    (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->asyncflags & ASYNC_FLAGS);
+       new_serial.flags |= (info->port.flags & ASYNC_FLAGS);
 
        MoxaSetFifo(info, new_serial.type == PORT_16550A);