Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / serial / ip22zilog.c
index 93ce805..6517724 100644 (file)
@@ -47,8 +47,6 @@
 
 #include "ip22zilog.h"
 
-int ip22serial_current_minor = 64;
-
 void ip22_do_break(void);
 
 /*
@@ -59,10 +57,10 @@ void ip22_do_break(void);
 #define ZSDELAY_LONG()         udelay(20)
 #define ZS_WSYNC(channel)      do { } while (0)
 
-#define NUM_IP22ZILOG  1
-#define NUM_CHANNELS   (NUM_IP22ZILOG * 2)
+#define NUM_IP22ZILOG          1
+#define NUM_CHANNELS           (NUM_IP22ZILOG * 2)
 
-#define ZS_CLOCK               4915200 /* Zilog input clock rate. */
+#define ZS_CLOCK               3672000 /* Zilog input clock rate. */
 #define ZS_CLOCK_DIVISOR       16      /* Divisor this driver uses. */
 
 /*
@@ -86,7 +84,7 @@ struct uart_ip22zilog_port {
 #define IP22ZILOG_FLAG_TX_STOPPED      0x00000080
 #define IP22ZILOG_FLAG_TX_ACTIVE       0x00000100
 
-       unsigned int cflag;
+       unsigned int                    cflag;
 
        /* L1-A keyboard break state.  */
        int                             kbd_id;
@@ -217,7 +215,7 @@ static void __load_zsregs(struct zilog_channel *channel, unsigned char *regs)
        /* Lower and upper byte of baud rate generator divisor.  */
        write_zsreg(channel, R12, regs[R12]);
        write_zsreg(channel, R13, regs[R13]);
-       
+
        /* Now rewrite R14, with BRENAB (if set).  */
        write_zsreg(channel, R14, regs[R14]);
 
@@ -261,13 +259,7 @@ static void ip22zilog_receive_chars(struct uart_ip22zilog_port *up,
        struct tty_struct *tty = up->port.info->tty;    /* XXX info==NULL? */
 
        while (1) {
-               unsigned char ch, r1;
-
-               if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) {
-                       tty->flip.work.func((void *)tty);
-                       if (tty->flip.count >= TTY_FLIPBUF_SIZE)
-                               return;         /* XXX Ignores SysRq when we need it most. Fix. */
-               }
+               unsigned char ch, r1, flag;
 
                r1 = read_zsreg(channel, R1);
                if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) {
@@ -305,8 +297,7 @@ static void ip22zilog_receive_chars(struct uart_ip22zilog_port *up,
                }
 
                /* A real serial line, record the character and status.  */
-               *tty->flip.char_buf_ptr = ch;
-               *tty->flip.flag_buf_ptr = TTY_NORMAL;
+               flag = TTY_NORMAL;
                up->port.icount.rx++;
                if (r1 & (BRK_ABRT | PAR_ERR | Rx_OVR | CRC_ERR)) {
                        if (r1 & BRK_ABRT) {
@@ -323,28 +314,21 @@ static void ip22zilog_receive_chars(struct uart_ip22zilog_port *up,
                                up->port.icount.overrun++;
                        r1 &= up->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 (uart_handle_sysrq_char(&up->port, ch, regs))
                        goto next_char;
 
                if (up->port.ignore_status_mask == 0xff ||
-                   (r1 & up->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++;
-               }
+                   (r1 & up->port.ignore_status_mask) == 0)
+                       tty_insert_flip_char(tty, ch, flag);
+
+               if (r1 & Rx_OVR)
+                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
        next_char:
                ch = readb(&channel->control);
                ZSDELAY();
@@ -436,10 +420,8 @@ static void ip22zilog_transmit_chars(struct uart_ip22zilog_port *up,
        if (up->port.info == NULL)
                goto ack_tx_int;
        xmit = &up->port.info->xmit;
-       if (uart_circ_empty(xmit)) {
-               uart_write_wakeup(&up->port);
+       if (uart_circ_empty(xmit))
                goto ack_tx_int;
-       }
        if (uart_tx_stopped(&up->port))
                goto ack_tx_int;
 
@@ -520,27 +502,28 @@ static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id, struct pt_regs *re
 static __inline__ unsigned char ip22zilog_read_channel_status(struct uart_port *port)
 {
        struct zilog_channel *channel;
-       unsigned long flags;
        unsigned char status;
 
-       spin_lock_irqsave(&port->lock, flags);
-
        channel = ZILOG_CHANNEL_FROM_PORT(port);
        status = readb(&channel->control);
        ZSDELAY();
 
-       spin_unlock_irqrestore(&port->lock, flags);
-
        return status;
 }
 
 /* The port lock is not held.  */
 static unsigned int ip22zilog_tx_empty(struct uart_port *port)
 {
+       unsigned long flags;
        unsigned char status;
        unsigned int ret;
 
+       spin_lock_irqsave(&port->lock, flags);
+
        status = ip22zilog_read_channel_status(port);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+
        if (status & Tx_BUF_EMP)
                ret = TIOCSER_TEMT;
        else
@@ -549,7 +532,7 @@ static unsigned int ip22zilog_tx_empty(struct uart_port *port)
        return ret;
 }
 
-/* The port lock is not held.  */
+/* The port lock is held and interrupts are disabled.  */
 static unsigned int ip22zilog_get_mctrl(struct uart_port *port)
 {
        unsigned char status;
@@ -586,14 +569,14 @@ static void ip22zilog_set_mctrl(struct uart_port *port, unsigned int mctrl)
        else
                clear_bits |= DTR;
 
-       /* NOTE: Not subject to 'transmitter active' rule.  */ 
+       /* NOTE: Not subject to 'transmitter active' rule.  */
        up->curregs[R5] |= set_bits;
        up->curregs[R5] &= ~clear_bits;
        write_zsreg(channel, R5, up->curregs[R5]);
 }
 
 /* The port lock is held and interrupts are disabled.  */
-static void ip22zilog_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void ip22zilog_stop_tx(struct uart_port *port)
 {
        struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
 
@@ -601,7 +584,7 @@ static void ip22zilog_stop_tx(struct uart_port *port, unsigned int tty_stop)
 }
 
 /* The port lock is held and interrupts are disabled.  */
-static void ip22zilog_start_tx(struct uart_port *port, unsigned int tty_start)
+static void ip22zilog_start_tx(struct uart_port *port)
 {
        struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
        struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);
@@ -642,46 +625,36 @@ static void ip22zilog_start_tx(struct uart_port *port, unsigned int tty_start)
        }
 }
 
-/* The port lock is not held.  */
+/* The port lock is held and interrupts are disabled.  */
 static void ip22zilog_stop_rx(struct uart_port *port)
 {
        struct uart_ip22zilog_port *up = UART_ZILOG(port);
        struct zilog_channel *channel;
-       unsigned long flags;
 
        if (ZS_IS_CONS(up))
                return;
 
-       spin_lock_irqsave(&port->lock, flags);
-
        channel = ZILOG_CHANNEL_FROM_PORT(port);
 
        /* Disable all RX interrupts.  */
        up->curregs[R1] &= ~RxINT_MASK;
        ip22zilog_maybe_update_regs(up, channel);
-
-       spin_unlock_irqrestore(&port->lock, flags);
 }
 
-/* The port lock is not held.  */
+/* The port lock is held.  */
 static void ip22zilog_enable_ms(struct uart_port *port)
 {
        struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
        struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);
        unsigned char new_reg;
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
 
        new_reg = up->curregs[R15] | (DCDIE | SYNCIE | CTSIE);
        if (new_reg != up->curregs[R15]) {
                up->curregs[R15] = new_reg;
 
-               /* NOTE: Not subject to 'transmitter active' rule.  */ 
+               /* NOTE: Not subject to 'transmitter active' rule.  */
                write_zsreg(channel, R15, up->curregs[R15]);
        }
-
-       spin_unlock_irqrestore(&port->lock, flags);
 }
 
 /* The port lock is not held.  */
@@ -705,7 +678,7 @@ static void ip22zilog_break_ctl(struct uart_port *port, int break_state)
        if (new_reg != up->curregs[R5]) {
                up->curregs[R5] = new_reg;
 
-               /* NOTE: Not subject to 'transmitter active' rule.  */ 
+               /* NOTE: Not subject to 'transmitter active' rule.  */
                write_zsreg(channel, R5, up->curregs[R5]);
        }
 
@@ -807,7 +780,7 @@ ip22zilog_convert_to_zs(struct uart_ip22zilog_port *up, unsigned int cflag,
        up->curregs[R4] |= X16CLK;
        up->curregs[R12] = brg & 0xff;
        up->curregs[R13] = (brg >> 8) & 0xff;
-       up->curregs[R14] = BRSRC | BRENAB;
+       up->curregs[R14] = BRENAB;
 
        /* Character size, stop bits, and parity. */
        up->curregs[3] &= ~RxN_MASK;
@@ -950,13 +923,6 @@ static struct zilog_layout **ip22zilog_chip_regs;
 static struct uart_ip22zilog_port *ip22zilog_irq_chain;
 static int zilog_irq = -1;
 
-static struct uart_driver ip22zilog_reg = {
-       .owner          =       THIS_MODULE,
-       .driver_name    =       "ttyS",
-       .devfs_name     =       "tty/",
-       .major          =       TTY_MAJOR,
-};
-
 static void * __init alloc_one_table(unsigned long size)
 {
        void *ret;
@@ -990,7 +956,7 @@ static struct zilog_layout * __init get_zs(int chip)
        }
 
        /* Not probe-able, hard code it. */
-       base = (unsigned long) &sgioc->serport;
+       base = (unsigned long) &sgioc->uart;
 
        zilog_irq = SGI_SERIAL_IRQ;
        request_mem_region(base, 8, "IP22-Zilog");
@@ -1001,8 +967,9 @@ static struct zilog_layout * __init get_zs(int chip)
 #define ZS_PUT_CHAR_MAX_DELAY  2000    /* 10 ms */
 
 #ifdef CONFIG_SERIAL_IP22_ZILOG_CONSOLE
-static void ip22zilog_put_char(struct zilog_channel *channel, unsigned char ch)
+static void ip22zilog_put_char(struct uart_port *port, int ch)
 {
+       struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);
        int loops = ZS_PUT_CHAR_MAX_DELAY;
 
        /* This is a timed polling loop so do not switch the explicit
@@ -1026,16 +993,10 @@ static void
 ip22zilog_console_write(struct console *con, const char *s, unsigned int count)
 {
        struct uart_ip22zilog_port *up = &ip22zilog_port_table[con->index];
-       struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
        unsigned long flags;
-       int i;
 
        spin_lock_irqsave(&up->port.lock, flags);
-       for (i = 0; i < count; i++, s++) {
-               ip22zilog_put_char(channel, *s);
-               if (*s == 10)
-                       ip22zilog_put_char(channel, 13);
-       }
+       uart_console_write(&up->port, s, count, ip22zilog_put_char);
        udelay(2);
        spin_unlock_irqrestore(&up->port.lock, flags);
 }
@@ -1047,9 +1008,6 @@ ip22serial_console_termios(struct console *con, char *options)
        int parity = 'n';
        int flow = 'n';
 
-       if (!serial_console)
-               return;
-
        if (options)
                uart_parse_options(options, &baud, &parity, &bits, &flow);
 
@@ -1077,8 +1035,7 @@ static int __init ip22zilog_console_setup(struct console *con, char *options)
        unsigned long flags;
        int baud, brg;
 
-       printk("Console: ttyS%d (IP22-Zilog)\n",
-              (ip22zilog_reg.minor - 64) + con->index);
+       printk("Console: ttyS%d (IP22-Zilog)\n", con->index);
 
        /* Get firmware console settings.  */
        ip22serial_console_termios(con, options);
@@ -1112,6 +1069,8 @@ static int __init ip22zilog_console_setup(struct console *con, char *options)
        return 0;
 }
 
+static struct uart_driver ip22zilog_reg;
+
 static struct console ip22zilog_console = {
        .name   =       "ttyS",
        .write  =       ip22zilog_console_write,
@@ -1121,32 +1080,20 @@ static struct console ip22zilog_console = {
        .index  =       -1,
        .data   =       &ip22zilog_reg,
 };
-#define IP22ZILOG_CONSOLE      (&ip22zilog_console)
-
-static int __init ip22zilog_console_init(void)
-{
-       int i;
-
-       if (con_is_present())
-               return 0;
+#endif /* CONFIG_SERIAL_IP22_ZILOG_CONSOLE */
 
-       for (i = 0; i < NUM_CHANNELS; i++) {
-               int this_minor = ip22zilog_reg.minor + i;
-
-               if ((this_minor - 64) == (serial_console - 1))
-                       break;
-       }
-       if (i == NUM_CHANNELS)
-               return 0;
-
-       ip22zilog_console.index = i;
-       register_console(&ip22zilog_console);
-       return 0;
-}
-#else /* CONFIG_SERIAL_IP22_ZILOG_CONSOLE */
-#define IP22ZILOG_CONSOLE              (NULL)
-#define ip22zilog_console_init()       do { } while (0)
+static struct uart_driver ip22zilog_reg = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "serial",
+       .devfs_name     = "tts/",
+       .dev_name       = "ttyS",
+       .major          = TTY_MAJOR,
+       .minor          = 64,
+       .nr             = NUM_CHANNELS,
+#ifdef CONFIG_SERIAL_IP22_ZILOG_CONSOLE
+       .cons           = &ip22zilog_console,
 #endif
+};
 
 static void __init ip22zilog_prepare(void)
 {
@@ -1160,17 +1107,24 @@ static void __init ip22zilog_prepare(void)
        for (channel = 0; channel < NUM_CHANNELS; channel++)
                spin_lock_init(&ip22zilog_port_table[channel].port.lock);
 
-       ip22zilog_irq_chain = up = &ip22zilog_port_table[0];
-       for (channel = 0; channel < NUM_CHANNELS - 1; channel++)
-               up[channel].next = &up[channel + 1];
+       ip22zilog_irq_chain = &ip22zilog_port_table[NUM_CHANNELS - 1];
+        up = &ip22zilog_port_table[0];
+       for (channel = NUM_CHANNELS - 1 ; channel > 0; channel--)
+               up[channel].next = &up[channel - 1];
        up[channel].next = NULL;
 
        for (chip = 0; chip < NUM_IP22ZILOG; chip++) {
                if (!ip22zilog_chip_regs[chip]) {
                        ip22zilog_chip_regs[chip] = rp = get_zs(chip);
 
-                       up[(chip * 2) + 0].port.membase = (char *) &rp->channelA;
-                       up[(chip * 2) + 1].port.membase = (char *) &rp->channelB;
+                       up[(chip * 2) + 0].port.membase = (char *) &rp->channelB;
+                       up[(chip * 2) + 1].port.membase = (char *) &rp->channelA;
+
+                       /* In theory mapbase is the physical address ...  */
+                       up[(chip * 2) + 0].port.mapbase =
+                               (unsigned long) ioremap((unsigned long) &rp->channelB, 8);
+                       up[(chip * 2) + 1].port.mapbase =
+                               (unsigned long) ioremap((unsigned long) &rp->channelA, 8);
                }
 
                /* Channel A */
@@ -1182,7 +1136,7 @@ static void __init ip22zilog_prepare(void)
                up[(chip * 2) + 0].port.type = PORT_IP22ZILOG;
                up[(chip * 2) + 0].port.flags = 0;
                up[(chip * 2) + 0].port.line = (chip * 2) + 0;
-               up[(chip * 2) + 0].flags |= IP22ZILOG_FLAG_IS_CHANNEL_A;
+               up[(chip * 2) + 0].flags = 0;
 
                /* Channel B */
                up[(chip * 2) + 1].port.iotype = UPIO_MEM;
@@ -1191,9 +1145,9 @@ static void __init ip22zilog_prepare(void)
                up[(chip * 2) + 1].port.fifosize = 1;
                up[(chip * 2) + 1].port.ops = &ip22zilog_pops;
                up[(chip * 2) + 1].port.type = PORT_IP22ZILOG;
-               up[(chip * 2) + 1].port.flags = 0;
+               up[(chip * 2) + 1].port.flags |= IP22ZILOG_FLAG_IS_CHANNEL_A;
                up[(chip * 2) + 1].port.line = (chip * 2) + 1;
-               up[(chip * 2) + 1].flags |= 0;
+               up[(chip * 2) + 1].flags = 0;
        }
 }
 
@@ -1228,8 +1182,10 @@ static void __init ip22zilog_init_hw(void)
                brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR);
                up->curregs[R12] = (brg & 0xff);
                up->curregs[R13] = (brg >> 8) & 0xff;
-               up->curregs[R14] = BRSRC | BRENAB;
+               up->curregs[R14] = BRENAB;
                __load_zsregs(channel, up->curregs);
+               /* set master interrupt enable */
+               write_zsreg(channel, R9, up->curregs[R9]);
 
                spin_unlock_irqrestore(&up->port.lock, flags);
        }
@@ -1250,15 +1206,6 @@ static int __init ip22zilog_ports_init(void)
 
        ip22zilog_init_hw();
 
-       /* We can only init this once we have probed the Zilogs
-        * in the system.
-        */
-       ip22zilog_reg.nr = NUM_CHANNELS;
-       ip22zilog_reg.cons = IP22ZILOG_CONSOLE;
-
-       ip22zilog_reg.minor = ip22serial_current_minor;
-       ip22serial_current_minor += NUM_CHANNELS;
-
        ret = uart_register_driver(&ip22zilog_reg);
        if (ret == 0) {
                int i;
@@ -1276,11 +1223,8 @@ static int __init ip22zilog_ports_init(void)
 static int __init ip22zilog_init(void)
 {
        /* IP22 Zilog setup is hard coded, no probing to do.  */
-
        ip22zilog_alloc_tables();
-
        ip22zilog_ports_init();
-       ip22zilog_console_init();
 
        return 0;
 }