[PATCH] tty: switch to ktermios
[safe/jmp/linux-2.6] / drivers / serial / pmac_zilog.c
index 85abd8a..752ef07 100644 (file)
@@ -42,7 +42,6 @@
 #undef DEBUG_HARD
 #undef USE_CTRL_O_SYSRQ
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/tty.h>
 
@@ -60,6 +59,7 @@
 #include <linux/pmu.h>
 #include <linux/bitops.h>
 #include <linux/sysrq.h>
+#include <linux/mutex.h>
 #include <asm/sections.h>
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -68,7 +68,6 @@
 #include <asm/pmac_feature.h>
 #include <asm/dbdma.h>
 #include <asm/macio.h>
-#include <asm/semaphore.h>
 
 #if defined (CONFIG_SERIAL_PMACZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
 #define SUPPORT_SYSRQ
@@ -96,12 +95,11 @@ MODULE_LICENSE("GPL");
  */
 static struct uart_pmac_port   pmz_ports[MAX_ZS_PORTS];
 static int                     pmz_ports_count;
-static DECLARE_MUTEX(pmz_irq_sem);
+static DEFINE_MUTEX(pmz_irq_mutex);
 
 static struct uart_driver pmz_uart_reg = {
        .owner          =       THIS_MODULE,
        .driver_name    =       "ttyS",
-       .devfs_name     =       "tts/",
        .dev_name       =       "ttyS",
        .major          =       TTY_MAJOR,
 };
@@ -206,14 +204,12 @@ static void pmz_maybe_update_regs(struct uart_pmac_port *uap)
        }
 }
 
-static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap,
-                                           struct pt_regs *regs)
+static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap)
 {
        struct tty_struct *tty = NULL;
-       unsigned char ch, r1, drop, error;
+       unsigned char ch, r1, drop, error, flag;
        int loops = 0;
 
- retry:
        /* The interrupt can be enabled when the port isn't open, typically
         * that happens when using one port is open and the other closed (stale
         * interrupt) or when one port is used as a console.
@@ -246,20 +242,6 @@ static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap,
                error = 0;
                drop = 0;
 
-               if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) {
-                       /* Have to drop the lock here */
-                       pmz_debug("pmz: flip overflow\n");
-                       spin_unlock(&uap->port.lock);
-                       tty->flip.work.func((void *)tty);
-                       spin_lock(&uap->port.lock);
-                       if (tty->flip.count >= TTY_FLIPBUF_SIZE)
-                               drop = 1;
-                       if (ZS_IS_ASLEEP(uap))
-                               return NULL;
-                       if (!ZS_IS_OPEN(uap))
-                               goto retry;
-               }
-
                r1 = read_zsreg(uap, R1);
                ch = read_zsdata(uap);
 
@@ -284,7 +266,7 @@ static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap,
                if (uap->port.sysrq) {
                        int swallow;
                        spin_unlock(&uap->port.lock);
-                       swallow = uart_handle_sysrq_char(&uap->port, ch, regs);
+                       swallow = uart_handle_sysrq_char(&uap->port, ch);
                        spin_lock(&uap->port.lock);
                        if (swallow)
                                goto next_char;
@@ -295,8 +277,7 @@ static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap,
                if (drop)
                        goto next_char;
 
-               *tty->flip.char_buf_ptr = ch;
-               *tty->flip.flag_buf_ptr = TTY_NORMAL;
+               flag = TTY_NORMAL;
                uap->port.icount.rx++;
 
                if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR | BRK_ABRT)) {
@@ -316,26 +297,19 @@ static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap,
                                uap->port.icount.overrun++;
                        r1 &= uap->port.read_status_mask;
                        if (r1 & BRK_ABRT)
-                               *tty->flip.flag_buf_ptr = TTY_BREAK;
+                               flag = TTY_BREAK;
                        else if (r1 & PAR_ERR)
-                               *tty->flip.flag_buf_ptr = TTY_PARITY;
+                               flag = TTY_PARITY;
                        else if (r1 & CRC_ERR)
-                               *tty->flip.flag_buf_ptr = TTY_FRAME;
+                               flag = TTY_FRAME;
                }
 
                if (uap->port.ignore_status_mask == 0xff ||
                    (r1 & uap->port.ignore_status_mask) == 0) {
-                       tty->flip.flag_buf_ptr++;
-                       tty->flip.char_buf_ptr++;
-                       tty->flip.count++;
-               }
-               if ((r1 & Rx_OVR) &&
-                   tty->flip.count < TTY_FLIPBUF_SIZE) {
-                       *tty->flip.flag_buf_ptr = TTY_OVERRUN;
-                       tty->flip.flag_buf_ptr++;
-                       tty->flip.char_buf_ptr++;
-                       tty->flip.count++;
+                       tty_insert_flip_char(tty, ch, flag);
                }
+               if (r1 & Rx_OVR)
+                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
        next_char:
                /* We can get stuck in an infinite loop getting char 0 when the
                 * line is in a wrong HW state, we break that here.
@@ -360,7 +334,7 @@ static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap,
        return tty;
 }
 
-static void pmz_status_handle(struct uart_pmac_port *uap, struct pt_regs *regs)
+static void pmz_status_handle(struct uart_pmac_port *uap)
 {
        unsigned char status;
 
@@ -463,7 +437,7 @@ ack_tx_int:
 }
 
 /* Hrm... we register that twice, fixme later.... */
-static irqreturn_t pmz_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t pmz_interrupt(int irq, void *dev_id)
 {
        struct uart_pmac_port *uap = dev_id;
        struct uart_pmac_port *uap_a;
@@ -487,9 +461,9 @@ static irqreturn_t pmz_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                write_zsreg(uap_a, R0, RES_H_IUS);
                zssync(uap_a);          
                        if (r3 & CHAEXT)
-                               pmz_status_handle(uap_a, regs);
+                               pmz_status_handle(uap_a);
                if (r3 & CHARxIP)
-                       tty = pmz_receive_chars(uap_a, regs);
+                       tty = pmz_receive_chars(uap_a);
                        if (r3 & CHATxIP)
                                pmz_transmit_chars(uap_a);
                rc = IRQ_HANDLED;
@@ -507,9 +481,9 @@ static irqreturn_t pmz_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                write_zsreg(uap_b, R0, RES_H_IUS);
                zssync(uap_b);
                        if (r3 & CHBEXT)
-                               pmz_status_handle(uap_b, regs);
+                               pmz_status_handle(uap_b);
                        if (r3 & CHBRxIP)
-                               tty = pmz_receive_chars(uap_b, regs);
+                               tty = pmz_receive_chars(uap_b);
                        if (r3 & CHBTxIP)
                                pmz_transmit_chars(uap_b);
                rc = IRQ_HANDLED;
@@ -604,7 +578,7 @@ static void pmz_set_mctrl(struct uart_port *port, unsigned int mctrl)
 /* 
  * Get Modem Control bits (only the input ones, the core will
  * or that with a cached value of the control ones)
- * The port lock is not held.
+ * The port lock is held and interrupts are disabled.
  */
 static unsigned int pmz_get_mctrl(struct uart_port *port)
 {
@@ -615,7 +589,7 @@ static unsigned int pmz_get_mctrl(struct uart_port *port)
        if (ZS_IS_ASLEEP(uap) || uap->node == NULL)
                return 0;
 
-       status = pmz_peek_status(to_pmz(port));
+       status = read_zsreg(uap, R0);
 
        ret = 0;
        if (status & DCD)
@@ -630,11 +604,10 @@ static unsigned int pmz_get_mctrl(struct uart_port *port)
 
 /* 
  * Stop TX side. Dealt like sunzilog at next Tx interrupt,
- * though for DMA, we will have to do a bit more. What is
- * the meaning of the tty_stop bit ? XXX
+ * though for DMA, we will have to do a bit more.
  * The port lock is held and interrupts are disabled.
  */
-static void pmz_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void pmz_stop_tx(struct uart_port *port)
 {
        to_pmz(port)->flags |= PMACZILOG_FLAG_TX_STOPPED;
 }
@@ -643,7 +616,7 @@ static void pmz_stop_tx(struct uart_port *port, unsigned int tty_stop)
  * Kick the Tx side.
  * The port lock is held and interrupts are disabled.
  */
-static void pmz_start_tx(struct uart_port *port, unsigned int tty_start)
+static void pmz_start_tx(struct uart_port *port)
 {
        struct uart_pmac_port *uap = to_pmz(port);
        unsigned char status;
@@ -946,7 +919,7 @@ static int pmz_startup(struct uart_port *port)
        if (uap->node == NULL)
                return -ENODEV;
 
-       down(&pmz_irq_sem);
+       mutex_lock(&pmz_irq_mutex);
 
        uap->flags |= PMACZILOG_FLAG_IS_OPEN;
 
@@ -960,15 +933,15 @@ static int pmz_startup(struct uart_port *port)
        }       
 
        pmz_get_port_A(uap)->flags |= PMACZILOG_FLAG_IS_IRQ_ON;
-       if (request_irq(uap->port.irq, pmz_interrupt, SA_SHIRQ, "PowerMac Zilog", uap)) {
+       if (request_irq(uap->port.irq, pmz_interrupt, IRQF_SHARED, "PowerMac Zilog", uap)) {
                dev_err(&uap->dev->ofdev.dev,
                        "Unable to register zs interrupt handler.\n");
                pmz_set_scc_power(uap, 0);
-               up(&pmz_irq_sem);
+               mutex_unlock(&pmz_irq_mutex);
                return -ENXIO;
        }
 
-       up(&pmz_irq_sem);
+       mutex_unlock(&pmz_irq_mutex);
 
        /* Right now, we deal with delay by blocking here, I'll be
         * smarter later on
@@ -1005,7 +978,7 @@ static void pmz_shutdown(struct uart_port *port)
        if (uap->node == NULL)
                return;
 
-       down(&pmz_irq_sem);
+       mutex_lock(&pmz_irq_mutex);
 
        /* Release interrupt handler */
                free_irq(uap->port.irq, uap);
@@ -1026,7 +999,7 @@ static void pmz_shutdown(struct uart_port *port)
 
        if (ZS_IS_CONS(uap) || ZS_IS_ASLEEP(uap)) {
                spin_unlock_irqrestore(&port->lock, flags);
-               up(&pmz_irq_sem);
+               mutex_unlock(&pmz_irq_mutex);
                return;
        }
 
@@ -1043,7 +1016,7 @@ static void pmz_shutdown(struct uart_port *port)
 
        spin_unlock_irqrestore(&port->lock, flags);
 
-       up(&pmz_irq_sem);
+       mutex_unlock(&pmz_irq_mutex);
 
        pmz_debug("pmz: shutdown() done.\n");
 }
@@ -1289,8 +1262,8 @@ static void pmz_irda_setup(struct uart_pmac_port *uap, unsigned long *baud)
 }
 
 
-static void __pmz_set_termios(struct uart_port *port, struct termios *termios,
-                             struct termios *old)
+static void __pmz_set_termios(struct uart_port *port, struct ktermios *termios,
+                             struct ktermios *old)
 {
        struct uart_pmac_port *uap = to_pmz(port);
        unsigned long baud;
@@ -1300,7 +1273,7 @@ static void __pmz_set_termios(struct uart_port *port, struct termios *termios,
        if (ZS_IS_ASLEEP(uap))
                return;
 
-       memcpy(&uap->termios_cache, termios, sizeof(struct termios));
+       memcpy(&uap->termios_cache, termios, sizeof(struct ktermios));
 
        /* XXX Check which revs of machines actually allow 1 and 4Mb speeds
         * on the IR dongle. Note that the IRTTY driver currently doesn't know
@@ -1340,8 +1313,8 @@ static void __pmz_set_termios(struct uart_port *port, struct termios *termios,
 }
 
 /* The port lock is not held.  */
-static void pmz_set_termios(struct uart_port *port, struct termios *termios,
-                           struct termios *old)
+static void pmz_set_termios(struct uart_port *port, struct ktermios *termios,
+                           struct ktermios *old)
 {
        struct uart_pmac_port *uap = to_pmz(port);
        unsigned long flags;
@@ -1426,17 +1399,20 @@ static struct uart_ops pmz_pops = {
 static int __init pmz_init_port(struct uart_pmac_port *uap)
 {
        struct device_node *np = uap->node;
-       char *conn;
-       struct slot_names_prop {
+       const char *conn;
+       const struct slot_names_prop {
                int     count;
                char    name[1];
        } *slots;
        int len;
+       struct resource r_ports, r_rxdma, r_txdma;
 
        /*
         * Request & map chip registers
         */
-       uap->port.mapbase = np->addrs[0].address;
+       if (of_address_to_resource(np, 0, &r_ports))
+               return -ENODEV;
+       uap->port.mapbase = r_ports.start;
        uap->port.membase = ioremap(uap->port.mapbase, 0x1000);
       
        uap->control_reg = uap->port.membase;
@@ -1446,24 +1422,28 @@ static int __init pmz_init_port(struct uart_pmac_port *uap)
         * Request & map DBDMA registers
         */
 #ifdef HAS_DBDMA
-       if (np->n_addrs >= 3 && np->n_intrs >= 3)
+       if (of_address_to_resource(np, 1, &r_txdma) == 0 &&
+           of_address_to_resource(np, 2, &r_rxdma) == 0)
                uap->flags |= PMACZILOG_FLAG_HAS_DMA;
+#else
+       memset(&r_txdma, 0, sizeof(struct resource));
+       memset(&r_rxdma, 0, sizeof(struct resource));
 #endif 
        if (ZS_HAS_DMA(uap)) {
-               uap->tx_dma_regs = ioremap(np->addrs[np->n_addrs - 2].address, 0x1000);
+               uap->tx_dma_regs = ioremap(r_txdma.start, 0x100);
                if (uap->tx_dma_regs == NULL) { 
                        uap->flags &= ~PMACZILOG_FLAG_HAS_DMA;
                        goto no_dma;
                }
-               uap->rx_dma_regs = ioremap(np->addrs[np->n_addrs - 1].address, 0x1000);
+               uap->rx_dma_regs = ioremap(r_rxdma.start, 0x100);
                if (uap->rx_dma_regs == NULL) { 
                        iounmap(uap->tx_dma_regs);
                        uap->tx_dma_regs = NULL;
                        uap->flags &= ~PMACZILOG_FLAG_HAS_DMA;
                        goto no_dma;
                }
-               uap->tx_dma_irq = np->intrs[1].line;
-               uap->rx_dma_irq = np->intrs[2].line;
+               uap->tx_dma_irq = irq_of_parse_and_map(np, 1);
+               uap->rx_dma_irq = irq_of_parse_and_map(np, 2);
        }
 no_dma:
 
@@ -1477,7 +1457,7 @@ no_dma:
                uap->flags |= PMACZILOG_FLAG_IS_IRDA;
        uap->port_type = PMAC_SCC_ASYNC;
        /* 1999 Powerbook G3 has slot-names property instead */
-       slots = (struct slot_names_prop *)get_property(np, "slot-names", &len);
+       slots = get_property(np, "slot-names", &len);
        if (slots && slots->count > 0) {
                if (strcmp(slots->name, "IrDA") == 0)
                        uap->flags |= PMACZILOG_FLAG_IS_IRDA;
@@ -1489,7 +1469,8 @@ no_dma:
        if (ZS_IS_INTMODEM(uap)) {
                struct device_node* i2c_modem = find_devices("i2c-modem");
                if (i2c_modem) {
-                       char* mid = get_property(i2c_modem, "modem-id", NULL);
+                       const char* mid =
+                               get_property(i2c_modem, "modem-id", NULL);
                        if (mid) switch(*mid) {
                        case 0x04 :
                        case 0x05 :
@@ -1509,8 +1490,8 @@ no_dma:
        /*
         * Init remaining bits of "port" structure
         */
-       uap->port.iotype = SERIAL_IO_MEM;
-       uap->port.irq = np->intrs[0].line;
+       uap->port.iotype = UPIO_MEM;
+       uap->port.irq = irq_of_parse_and_map(np, 0);
        uap->port.uartclk = ZS_CLOCK;
        uap->port.fifosize = 1;
        uap->port.ops = &pmz_pops;
@@ -1545,7 +1526,7 @@ static void pmz_dispose_port(struct uart_pmac_port *uap)
 /*
  * Called upon match with an escc node in the devive-tree.
  */
-static int pmz_attach(struct macio_dev *mdev, const struct of_match *match)
+static int pmz_attach(struct macio_dev *mdev, const struct of_device_id *match)
 {
        int i;
        
@@ -1601,15 +1582,15 @@ static int pmz_suspend(struct macio_dev *mdev, pm_message_t pm_state)
                return 0;
        }
 
-       if (pm_state == mdev->ofdev.dev.power.power_state || pm_state < 2)
+       if (pm_state.event == mdev->ofdev.dev.power.power_state.event)
                return 0;
 
        pmz_debug("suspend, switching to state %d\n", pm_state);
 
        state = pmz_uart_reg.state + uap->port.line;
 
-       down(&pmz_irq_sem);
-       down(&state->sem);
+       mutex_lock(&pmz_irq_mutex);
+       mutex_lock(&state->mutex);
 
        spin_lock_irqsave(&uap->port.lock, flags);
 
@@ -1640,8 +1621,8 @@ static int pmz_suspend(struct macio_dev *mdev, pm_message_t pm_state)
        /* Shut the chip down */
        pmz_set_scc_power(uap, 0);
 
-       up(&state->sem);
-       up(&pmz_irq_sem);
+       mutex_unlock(&state->mutex);
+       mutex_unlock(&pmz_irq_mutex);
 
        pmz_debug("suspend, switching complete\n");
 
@@ -1661,15 +1642,15 @@ static int pmz_resume(struct macio_dev *mdev)
        if (uap == NULL)
                return 0;
 
-       if (mdev->ofdev.dev.power.power_state == 0)
+       if (mdev->ofdev.dev.power.power_state.event == PM_EVENT_ON)
                return 0;
        
        pmz_debug("resume, switching to state 0\n");
 
        state = pmz_uart_reg.state + uap->port.line;
 
-       down(&pmz_irq_sem);
-       down(&state->sem);
+       mutex_lock(&pmz_irq_mutex);
+       mutex_lock(&state->mutex);
 
        spin_lock_irqsave(&uap->port.lock, flags);
        if (!ZS_IS_OPEN(uap) && !ZS_IS_CONS(uap)) {
@@ -1701,8 +1682,8 @@ static int pmz_resume(struct macio_dev *mdev)
        }
 
  bail:
-       up(&state->sem);
-       up(&pmz_irq_sem);
+       mutex_unlock(&state->mutex);
+       mutex_unlock(&pmz_irq_mutex);
 
        /* Right now, we deal with delay by blocking here, I'll be
         * smarter later on
@@ -1714,7 +1695,7 @@ static int pmz_resume(struct macio_dev *mdev)
 
        pmz_debug("resume, switching complete\n");
 
-       mdev->ofdev.dev.power.power_state = 0;
+       mdev->ofdev.dev.power.power_state.event = PM_EVENT_ON;
 
        return 0;
 }
@@ -1850,20 +1831,17 @@ err_out:
        return rc;
 }
 
-static struct of_match pmz_match[] = 
+static struct of_device_id pmz_match[] = 
 {
        {
        .name           = "ch-a",
-       .type           = OF_ANY_MATCH,
-       .compatible     = OF_ANY_MATCH
        },
        {
        .name           = "ch-b",
-       .type           = OF_ANY_MATCH,
-       .compatible     = OF_ANY_MATCH
        },
        {},
 };
+MODULE_DEVICE_TABLE (of, pmz_match);
 
 static struct macio_driver pmz_driver = 
 {
@@ -1936,6 +1914,16 @@ static void __exit exit_pmz(void)
 
 #ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE
 
+static void pmz_console_putchar(struct uart_port *port, int ch)
+{
+       struct uart_pmac_port *uap = (struct uart_pmac_port *)port;
+
+       /* Wait for the transmit buffer to empty. */
+       while ((read_zsreg(uap, R0) & Tx_BUF_EMP) == 0)
+               udelay(5);
+       write_zsdata(uap, ch);
+}
+
 /*
  * Print a string to the serial port trying not to disturb
  * any possible real use of the port...
@@ -1944,7 +1932,6 @@ static void pmz_console_write(struct console *con, const char *s, unsigned int c
 {
        struct uart_pmac_port *uap = &pmz_ports[con->index];
        unsigned long flags;
-       int i;
 
        if (ZS_IS_ASLEEP(uap))
                return;
@@ -1954,17 +1941,7 @@ static void pmz_console_write(struct console *con, const char *s, unsigned int c
        write_zsreg(uap, R1, uap->curregs[1] & ~TxINT_ENAB);
        write_zsreg(uap, R5, uap->curregs[5] | TxENABLE | RTS | DTR);
 
-       for (i = 0; i < count; i++) {
-               /* Wait for the transmit buffer to empty. */
-               while ((read_zsreg(uap, R0) & Tx_BUF_EMP) == 0)
-                       udelay(5);
-               write_zsdata(uap, s[i]);
-               if (s[i] == 10) {
-                       while ((read_zsreg(uap, R0) & Tx_BUF_EMP) == 0)
-                               udelay(5);
-                       write_zsdata(uap, R13);
-               }
-       }
+       uart_console_write(&uap->port, s, count, pmz_console_putchar);
 
        /* Restore the values in the registers. */
        write_zsreg(uap, R1, uap->curregs[1]);