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 / sunzilog.c
index 506e6e7..cd49ebb 100644 (file)
@@ -107,12 +107,12 @@ struct uart_sunzilog_port {
        unsigned char                   prev_status;
 
 #ifdef CONFIG_SERIO
-       struct serio                    serio;
+       struct serio                    *serio;
        int                             serio_open;
 #endif
 };
 
-#define ZILOG_CHANNEL_FROM_PORT(PORT)  ((struct zilog_channel *)((PORT)->membase))
+#define ZILOG_CHANNEL_FROM_PORT(PORT)  ((struct zilog_channel __iomem *)((PORT)->membase))
 #define UART_ZILOG(PORT)               ((struct uart_sunzilog_port *)(PORT))
 
 #define ZS_IS_KEYB(UP) ((UP)->flags & SUNZILOG_FLAG_CONS_KEYB)
@@ -133,7 +133,7 @@ struct uart_sunzilog_port {
  * The port lock must be held and local IRQs must be disabled
  * when {read,write}_zsreg is invoked.
  */
-static unsigned char read_zsreg(struct zilog_channel *channel,
+static unsigned char read_zsreg(struct zilog_channel __iomem *channel,
                                unsigned char reg)
 {
        unsigned char retval;
@@ -146,7 +146,7 @@ static unsigned char read_zsreg(struct zilog_channel *channel,
        return retval;
 }
 
-static void write_zsreg(struct zilog_channel *channel,
+static void write_zsreg(struct zilog_channel __iomem *channel,
                        unsigned char reg, unsigned char value)
 {
        sbus_writeb(reg, &channel->control);
@@ -155,7 +155,7 @@ static void write_zsreg(struct zilog_channel *channel,
        ZSDELAY();
 }
 
-static void sunzilog_clear_fifo(struct zilog_channel *channel)
+static void sunzilog_clear_fifo(struct zilog_channel __iomem *channel)
 {
        int i;
 
@@ -182,7 +182,7 @@ static void sunzilog_clear_fifo(struct zilog_channel *channel)
 /* This function must only be called when the TX is not busy.  The UART
  * port lock must be held and local interrupts disabled.
  */
-static void __load_zsregs(struct zilog_channel *channel, unsigned char *regs)
+static void __load_zsregs(struct zilog_channel __iomem *channel, unsigned char *regs)
 {
        int i;
 
@@ -258,7 +258,7 @@ static void __load_zsregs(struct zilog_channel *channel, unsigned char *regs)
  * The UART port lock must be held and local interrupts disabled.
  */
 static void sunzilog_maybe_update_regs(struct uart_sunzilog_port *up,
-                                      struct zilog_channel *channel)
+                                      struct zilog_channel __iomem *channel)
 {
        if (!ZS_REGS_HELD(up)) {
                if (ZS_TX_ACTIVE(up)) {
@@ -291,7 +291,7 @@ static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up,
                /* Stop-A is handled by drivers/char/keyboard.c now. */
 #ifdef CONFIG_SERIO
                if (up->serio_open)
-                       serio_interrupt(&up->serio, ch, 0, regs);
+                       serio_interrupt(up->serio, ch, 0, regs);
 #endif
        } else if (ZS_IS_MOUSE(up)) {
                int ret = suncore_mouse_baud_detection(ch, is_break);
@@ -306,19 +306,20 @@ static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up,
                case 0:
 #ifdef CONFIG_SERIO
                        if (up->serio_open)
-                               serio_interrupt(&up->serio, ch, 0, regs);
+                               serio_interrupt(up->serio, ch, 0, regs);
 #endif
                        break;
                };
        }
 }
 
-static void sunzilog_receive_chars(struct uart_sunzilog_port *up,
-                                  struct zilog_channel *channel,
-                                  struct pt_regs *regs)
+static struct tty_struct *
+sunzilog_receive_chars(struct uart_sunzilog_port *up,
+                      struct zilog_channel __iomem *channel,
+                      struct pt_regs *regs)
 {
        struct tty_struct *tty;
-       unsigned char ch, r1;
+       unsigned char ch, r1, flag;
 
        tty = NULL;
        if (up->port.info != NULL &&            /* Unopened serial console */
@@ -361,19 +362,8 @@ static void sunzilog_receive_chars(struct uart_sunzilog_port *up,
                        continue;
                }
 
-               if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) {
-                       tty->flip.work.func((void *)tty);
-                       /*
-                        * The 8250 bails out of the loop here,
-                        * but we need to read everything, or die.
-                        */
-                       if (tty->flip.count >= TTY_FLIPBUF_SIZE)
-                               continue;
-               }
-
                /* 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) {
@@ -390,36 +380,28 @@ static void sunzilog_receive_chars(struct uart_sunzilog_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))
                        continue;
 
                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++;
+                       tty_insert_flip_char(tty, ch, flag);
                }
+               if (r1 & Rx_OVR)
+                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
        }
 
-       if (tty)
-               tty_flip_buffer_push(tty);
+       return tty;
 }
 
 static void sunzilog_status_handle(struct uart_sunzilog_port *up,
-                                  struct zilog_channel *channel,
+                                  struct zilog_channel __iomem *channel,
                                   struct pt_regs *regs)
 {
        unsigned char status;
@@ -471,7 +453,7 @@ static void sunzilog_status_handle(struct uart_sunzilog_port *up,
 }
 
 static void sunzilog_transmit_chars(struct uart_sunzilog_port *up,
-                                   struct zilog_channel *channel)
+                                   struct zilog_channel __iomem *channel)
 {
        struct circ_buf *xmit;
 
@@ -517,10 +499,9 @@ static void sunzilog_transmit_chars(struct uart_sunzilog_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;
 
@@ -548,21 +529,23 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id, struct pt_regs *reg
        struct uart_sunzilog_port *up = dev_id;
 
        while (up) {
-               struct zilog_channel *channel
+               struct zilog_channel __iomem *channel
                        = ZILOG_CHANNEL_FROM_PORT(&up->port);
+               struct tty_struct *tty;
                unsigned char r3;
 
                spin_lock(&up->port.lock);
                r3 = read_zsreg(channel, R3);
 
                /* Channel A */
+               tty = NULL;
                if (r3 & (CHAEXT | CHATxIP | CHARxIP)) {
                        sbus_writeb(RES_H_IUS, &channel->control);
                        ZSDELAY();
                        ZS_WSYNC(channel);
 
                        if (r3 & CHARxIP)
-                               sunzilog_receive_chars(up, channel, regs);
+                               tty = sunzilog_receive_chars(up, channel, regs);
                        if (r3 & CHAEXT)
                                sunzilog_status_handle(up, channel, regs);
                        if (r3 & CHATxIP)
@@ -570,18 +553,22 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id, struct pt_regs *reg
                }
                spin_unlock(&up->port.lock);
 
+               if (tty)
+                       tty_flip_buffer_push(tty);
+
                /* Channel B */
                up = up->next;
                channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
 
                spin_lock(&up->port.lock);
+               tty = NULL;
                if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) {
                        sbus_writeb(RES_H_IUS, &channel->control);
                        ZSDELAY();
                        ZS_WSYNC(channel);
 
                        if (r3 & CHBRxIP)
-                               sunzilog_receive_chars(up, channel, regs);
+                               tty = sunzilog_receive_chars(up, channel, regs);
                        if (r3 & CHBEXT)
                                sunzilog_status_handle(up, channel, regs);
                        if (r3 & CHBTxIP)
@@ -589,6 +576,9 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id, struct pt_regs *reg
                }
                spin_unlock(&up->port.lock);
 
+               if (tty)
+                       tty_flip_buffer_push(tty);
+
                up = up->next;
        }
 
@@ -600,28 +590,29 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id, struct pt_regs *reg
  */
 static __inline__ unsigned char sunzilog_read_channel_status(struct uart_port *port)
 {
-       struct zilog_channel *channel;
-       unsigned long flags;
+       struct zilog_channel __iomem *channel;
        unsigned char status;
 
-       spin_lock_irqsave(&port->lock, flags);
-
        channel = ZILOG_CHANNEL_FROM_PORT(port);
        status = sbus_readb(&channel->control);
        ZSDELAY();
 
-       spin_unlock_irqrestore(&port->lock, flags);
-
        return status;
 }
 
 /* The port lock is not held.  */
 static unsigned int sunzilog_tx_empty(struct uart_port *port)
 {
+       unsigned long flags;
        unsigned char status;
        unsigned int ret;
 
+       spin_lock_irqsave(&port->lock, flags);
+
        status = sunzilog_read_channel_status(port);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+
        if (status & Tx_BUF_EMP)
                ret = TIOCSER_TEMT;
        else
@@ -630,7 +621,7 @@ static unsigned int sunzilog_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 sunzilog_get_mctrl(struct uart_port *port)
 {
        unsigned char status;
@@ -653,7 +644,7 @@ static unsigned int sunzilog_get_mctrl(struct uart_port *port)
 static void sunzilog_set_mctrl(struct uart_port *port, unsigned int mctrl)
 {
        struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
-       struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);
+       struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port);
        unsigned char set_bits, clear_bits;
 
        set_bits = clear_bits = 0;
@@ -674,7 +665,7 @@ static void sunzilog_set_mctrl(struct uart_port *port, unsigned int mctrl)
 }
 
 /* The port lock is held and interrupts are disabled.  */
-static void sunzilog_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void sunzilog_stop_tx(struct uart_port *port)
 {
        struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
 
@@ -682,10 +673,10 @@ static void sunzilog_stop_tx(struct uart_port *port, unsigned int tty_stop)
 }
 
 /* The port lock is held and interrupts are disabled.  */
-static void sunzilog_start_tx(struct uart_port *port, unsigned int tty_start)
+static void sunzilog_start_tx(struct uart_port *port)
 {
        struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
-       struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);
+       struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port);
        unsigned char status;
 
        up->flags |= SUNZILOG_FLAG_TX_ACTIVE;
@@ -727,7 +718,7 @@ static void sunzilog_start_tx(struct uart_port *port, unsigned int tty_start)
 static void sunzilog_stop_rx(struct uart_port *port)
 {
        struct uart_sunzilog_port *up = UART_ZILOG(port);
-       struct zilog_channel *channel;
+       struct zilog_channel __iomem *channel;
 
        if (ZS_IS_CONS(up))
                return;
@@ -743,7 +734,7 @@ static void sunzilog_stop_rx(struct uart_port *port)
 static void sunzilog_enable_ms(struct uart_port *port)
 {
        struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
-       struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);
+       struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port);
        unsigned char new_reg;
 
        new_reg = up->curregs[R15] | (DCDIE | SYNCIE | CTSIE);
@@ -759,7 +750,7 @@ static void sunzilog_enable_ms(struct uart_port *port)
 static void sunzilog_break_ctl(struct uart_port *port, int break_state)
 {
        struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
-       struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);
+       struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port);
        unsigned char set_bits, clear_bits, new_reg;
        unsigned long flags;
 
@@ -785,7 +776,7 @@ static void sunzilog_break_ctl(struct uart_port *port, int break_state)
 
 static void __sunzilog_startup(struct uart_sunzilog_port *up)
 {
-       struct zilog_channel *channel;
+       struct zilog_channel __iomem *channel;
 
        channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
        up->prev_status = sbus_readb(&channel->control);
@@ -840,7 +831,7 @@ static int sunzilog_startup(struct uart_port *port)
 static void sunzilog_shutdown(struct uart_port *port)
 {
        struct uart_sunzilog_port *up = UART_ZILOG(port);
-       struct zilog_channel *channel;
+       struct zilog_channel __iomem *channel;
        unsigned long flags;
 
        if (ZS_IS_CONS(up))
@@ -965,6 +956,8 @@ sunzilog_set_termios(struct uart_port *port, struct termios *termios,
 
        sunzilog_maybe_update_regs(up, ZILOG_CHANNEL_FROM_PORT(port));
 
+       uart_update_timeout(port, termios->c_cflag, baud);
+
        spin_unlock_irqrestore(&up->port.lock, flags);
 }
 
@@ -1016,7 +1009,7 @@ static struct uart_ops sunzilog_pops = {
 };
 
 static struct uart_sunzilog_port *sunzilog_port_table;
-static struct zilog_layout **sunzilog_chip_regs;
+static struct zilog_layout __iomem **sunzilog_chip_regs;
 
 static struct uart_sunzilog_port *sunzilog_irq_chain;
 static int zilog_irq = -1;
@@ -1042,10 +1035,10 @@ static void * __init alloc_one_table(unsigned long size)
 
 static void __init sunzilog_alloc_tables(void)
 {
-       sunzilog_port_table = (struct uart_sunzilog_port *)
+       sunzilog_port_table = 
                alloc_one_table(NUM_CHANNELS * sizeof(struct uart_sunzilog_port));
-       sunzilog_chip_regs = (struct zilog_layout **)
-               alloc_one_table(NUM_SUNZILOG * sizeof(struct zilog_layout *));
+       sunzilog_chip_regs = 
+               alloc_one_table(NUM_SUNZILOG * sizeof(struct zilog_layout __iomem *));
 
        if (sunzilog_port_table == NULL || sunzilog_chip_regs == NULL) {
                prom_printf("SunZilog: Cannot allocate tables.\n");
@@ -1058,9 +1051,9 @@ static void __init sunzilog_alloc_tables(void)
 /* We used to attempt to use the address property of the Zilog device node
  * but that totally is not necessary on sparc64.
  */
-static struct zilog_layout * __init get_zs_sun4u(int chip, int zsnode)
+static struct zilog_layout __iomem * __init get_zs_sun4u(int chip, int zsnode)
 {
-       unsigned long mapped_addr;
+       void __iomem *mapped_addr;
        unsigned int sun4u_ino;
        struct sbus_bus *sbus = NULL;
        struct sbus_dev *sdev = NULL;
@@ -1100,9 +1093,9 @@ static struct zilog_layout * __init get_zs_sun4u(int chip, int zsnode)
                apply_fhc_ranges(central_bus->child,
                                 &zsregs[0], 1);
                apply_central_ranges(central_bus, &zsregs[0], 1);
-               mapped_addr =
-                       (((u64)zsregs[0].which_io)<<32UL) |
-                       ((u64)zsregs[0].phys_addr);
+               mapped_addr = (void __iomem *)
+                       ((((u64)zsregs[0].which_io)<<32UL) |
+                       ((u64)zsregs[0].phys_addr));
        }
 
        if (zilog_irq == -1) {
@@ -1122,7 +1115,7 @@ static struct zilog_layout * __init get_zs_sun4u(int chip, int zsnode)
                }
        }
 
-       return (struct zilog_layout *) mapped_addr;
+       return (struct zilog_layout __iomem *) mapped_addr;
 }
 #else /* CONFIG_SPARC64 */
 
@@ -1130,10 +1123,10 @@ static struct zilog_layout * __init get_zs_sun4u(int chip, int zsnode)
  * XXX The sun4d case is utterly screwed: it tries to re-walk the tree
  * (for the 3rd time) in order to find bootbus and cpu. Streamline it.
  */
-static struct zilog_layout * __init get_zs_sun4cmd(int chip, int node)
+static struct zilog_layout __iomem * __init get_zs_sun4cmd(int chip, int node)
 {
        struct linux_prom_irqs irq_info[2];
-       unsigned long mapped_addr = 0;
+       void __iomem *mapped_addr = NULL;
        int zsnode, cpunode, bbnode;
        struct linux_prom_registers zsreg[4];
        struct resource res;
@@ -1219,12 +1212,12 @@ static struct zilog_layout * __init get_zs_sun4cmd(int chip, int node)
                prom_halt();
        }
 
-       return (struct zilog_layout *) mapped_addr;
+       return (struct zilog_layout __iomem *) mapped_addr;
 }
 #endif /* !(CONFIG_SPARC64) */
 
 /* Get the address of the registers for SunZilog instance CHIP.  */
-static struct zilog_layout * __init get_zs(int chip, int node)
+static struct zilog_layout __iomem * __init get_zs(int chip, int node)
 {
        if (chip < 0 || chip >= NUM_SUNZILOG) {
                prom_printf("SunZilog: Illegal chip number %d in get_zs.\n", chip);
@@ -1250,7 +1243,7 @@ static struct zilog_layout * __init get_zs(int chip, int node)
                zilog_irq = 12;
                res.end = (res.start + (8 - 1));
                res.flags = IORESOURCE_IO;
-               return (struct zilog_layout *) sbus_ioremap(&res, 0, 8, "SunZilog");
+               return sbus_ioremap(&res, 0, 8, "SunZilog");
        }
 
        return get_zs_sun4cmd(chip, node);
@@ -1259,8 +1252,9 @@ static struct zilog_layout * __init get_zs(int chip, int node)
 
 #define ZS_PUT_CHAR_MAX_DELAY  2000    /* 10 ms */
 
-static void sunzilog_put_char(struct zilog_channel *channel, unsigned char ch)
+static void sunzilog_putchar(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
@@ -1282,16 +1276,16 @@ static void sunzilog_put_char(struct zilog_channel *channel, unsigned char ch)
 
 #ifdef CONFIG_SERIO
 
-static spinlock_t sunzilog_serio_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(sunzilog_serio_lock);
 
 static int sunzilog_serio_write(struct serio *serio, unsigned char ch)
 {
-       struct uart_sunzilog_port *up = serio->driver;
+       struct uart_sunzilog_port *up = serio->port_data;
        unsigned long flags;
 
        spin_lock_irqsave(&sunzilog_serio_lock, flags);
 
-       sunzilog_put_char(ZILOG_CHANNEL_FROM_PORT(&up->port), ch);
+       sunzilog_putchar(&up->port, ch);
 
        spin_unlock_irqrestore(&sunzilog_serio_lock, flags);
 
@@ -1300,7 +1294,7 @@ static int sunzilog_serio_write(struct serio *serio, unsigned char ch)
 
 static int sunzilog_serio_open(struct serio *serio)
 {
-       struct uart_sunzilog_port *up = serio->driver;
+       struct uart_sunzilog_port *up = serio->port_data;
        unsigned long flags;
        int ret;
 
@@ -1317,7 +1311,7 @@ static int sunzilog_serio_open(struct serio *serio)
 
 static void sunzilog_serio_close(struct serio *serio)
 {
-       struct uart_sunzilog_port *up = serio->driver;
+       struct uart_sunzilog_port *up = serio->port_data;
        unsigned long flags;
 
        spin_lock_irqsave(&sunzilog_serio_lock, flags);
@@ -1332,16 +1326,10 @@ static void
 sunzilog_console_write(struct console *con, const char *s, unsigned int count)
 {
        struct uart_sunzilog_port *up = &sunzilog_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++) {
-               sunzilog_put_char(channel, *s);
-               if (*s == 10)
-                       sunzilog_put_char(channel, 13);
-       }
+       uart_console_write(&up->port, s, count, sunzilog_putchar);
        udelay(2);
        spin_unlock_irqrestore(&up->port.lock, flags);
 }
@@ -1397,7 +1385,6 @@ static struct console sunzilog_console = {
        .index  =       -1,
        .data   =       &sunzilog_reg,
 };
-#define SUNZILOG_CONSOLE       (&sunzilog_console)
 
 static int __init sunzilog_console_init(void)
 {
@@ -1420,8 +1407,31 @@ static int __init sunzilog_console_init(void)
        register_console(&sunzilog_console);
        return 0;
 }
+
+static inline struct console *SUNZILOG_CONSOLE(void)
+{
+       int i;
+
+       if (con_is_present())
+               return NULL;
+
+       for (i = 0; i < NUM_CHANNELS; i++) {
+               int this_minor = sunzilog_reg.minor + i;
+
+               if ((this_minor - 64) == (serial_console - 1))
+                       break;
+       }
+       if (i == NUM_CHANNELS)
+               return NULL;
+
+       sunzilog_console.index = i;
+       sunzilog_port_table[i].flags |= SUNZILOG_FLAG_IS_CONS;
+
+       return &sunzilog_console;
+}
+
 #else
-#define SUNZILOG_CONSOLE       (NULL)
+#define SUNZILOG_CONSOLE()     (NULL)
 #define sunzilog_console_init() do { } while (0)
 #endif
 
@@ -1474,7 +1484,7 @@ static void __init sunzilog_scan(struct zs_probe_scan *t, int node)
 static void __init sunzilog_prepare(void)
 {
        struct uart_sunzilog_port *up;
-       struct zilog_layout *rp;
+       struct zilog_layout __iomem *rp;
        int channel, chip;
 
        /*
@@ -1490,11 +1500,11 @@ static void __init sunzilog_prepare(void)
 
        for (chip = 0; chip < NUM_SUNZILOG; chip++) {
                rp = sunzilog_chip_regs[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 = (void __iomem *)&rp->channelA;
+               up[(chip * 2) + 1].port.membase = (void __iomem *)&rp->channelB;
 
                /* Channel A */
-               up[(chip * 2) + 0].port.iotype = SERIAL_IO_MEM;
+               up[(chip * 2) + 0].port.iotype = UPIO_MEM;
                up[(chip * 2) + 0].port.irq = zilog_irq;
                up[(chip * 2) + 0].port.uartclk = ZS_CLOCK;
                up[(chip * 2) + 0].port.fifosize = 1;
@@ -1505,7 +1515,7 @@ static void __init sunzilog_prepare(void)
                up[(chip * 2) + 0].flags |= SUNZILOG_FLAG_IS_CHANNEL_A;
 
                /* Channel B */
-               up[(chip * 2) + 1].port.iotype = SERIAL_IO_MEM;
+               up[(chip * 2) + 1].port.iotype = UPIO_MEM;
                up[(chip * 2) + 1].port.irq = zilog_irq;
                up[(chip * 2) + 1].port.uartclk = ZS_CLOCK;
                up[(chip * 2) + 1].port.fifosize = 1;
@@ -1536,33 +1546,45 @@ static void __init sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channe
        up->curregs[R15] = BRKIE;
        brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR);
        sunzilog_convert_to_zs(up, up->cflag, 0, brg);
+       sunzilog_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS);
+       __sunzilog_startup(up);
+}
 
 #ifdef CONFIG_SERIO
-       memset(&up->serio, 0, sizeof(up->serio));
+static void __init sunzilog_register_serio(struct uart_sunzilog_port *up, int channel)
+{
+       struct serio *serio;
 
-       up->serio.driver = up;
+       up->serio = serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
+       if (serio) {
+               memset(serio, 0, sizeof(*serio));
 
-       up->serio.type = SERIO_RS232;
-       if (channel == KEYBOARD_LINE) {
-               up->serio.type |= SERIO_SUNKBD;
-               up->serio.name = "zskbd";
-       } else {
-               up->serio.type |= (SERIO_SUN | (1 << 16));
-               up->serio.name = "zsms";
-       }
-       up->serio.phys = (channel == KEYBOARD_LINE ?
-                         "zs/serio0" : "zs/serio1");
+               serio->port_data = up;
 
-       up->serio.write = sunzilog_serio_write;
-       up->serio.open = sunzilog_serio_open;
-       up->serio.close = sunzilog_serio_close;
+               serio->id.type = SERIO_RS232;
+               if (channel == KEYBOARD_LINE) {
+                       serio->id.proto = SERIO_SUNKBD;
+                       strlcpy(serio->name, "zskbd", sizeof(serio->name));
+               } else {
+                       serio->id.proto = SERIO_SUN;
+                       serio->id.extra = 1;
+                       strlcpy(serio->name, "zsms", sizeof(serio->name));
+               }
+               strlcpy(serio->phys,
+                       (channel == KEYBOARD_LINE ? "zs/serio0" : "zs/serio1"),
+                       sizeof(serio->phys));
 
-       serio_register_port(&up->serio);
-#endif
+               serio->write = sunzilog_serio_write;
+               serio->open = sunzilog_serio_open;
+               serio->close = sunzilog_serio_close;
 
-       sunzilog_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS);
-       __sunzilog_startup(up);
+               serio_register_port(serio);
+       } else {
+               printk(KERN_WARNING "zs%d: not enough memory for serio port\n",
+                       channel);
+       }
 }
+#endif
 
 static void __init sunzilog_init_hw(void)
 {
@@ -1570,7 +1592,7 @@ static void __init sunzilog_init_hw(void)
 
        for (i = 0; i < NUM_CHANNELS; i++) {
                struct uart_sunzilog_port *up = &sunzilog_port_table[i];
-               struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
+               struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
                unsigned long flags;
                int baud, brg;
 
@@ -1606,10 +1628,15 @@ static void __init sunzilog_init_hw(void)
                }
 
                spin_unlock_irqrestore(&up->port.lock, flags);
+
+#ifdef CONFIG_SERIO
+               if (i == KEYBOARD_LINE || i == MOUSE_LINE)
+                       sunzilog_register_serio(up, i);
+#endif
        }
 }
 
-static struct zilog_layout * __init get_zs(int chip, int node);
+static struct zilog_layout __iomem * __init get_zs(int chip, int node);
 
 static void __init sunzilog_scan_probe(struct zs_probe_scan *t, int node)
 {
@@ -1656,13 +1683,15 @@ static int __init sunzilog_ports_init(void)
        }
                
        sunzilog_reg.nr = uart_count;
-       sunzilog_reg.cons = SUNZILOG_CONSOLE;
-
        sunzilog_reg.minor = sunserial_current_minor;
-       sunserial_current_minor += uart_count;
 
        ret = uart_register_driver(&sunzilog_reg);
        if (ret == 0) {
+               sunzilog_reg.tty_driver->name_base = sunzilog_reg.minor - 64;
+               sunzilog_reg.cons = SUNZILOG_CONSOLE();
+
+               sunserial_current_minor += uart_count;
+
                for (i = 0; i < NUM_CHANNELS; i++) {
                        struct uart_sunzilog_port *up = &sunzilog_port_table[i];
 
@@ -1711,7 +1740,6 @@ static int __init sunzilog_init(void)
        sunzilog_alloc_tables();
 
        sunzilog_ports_init();
-       sunzilog_console_init();
 
        return 0;
 }
@@ -1723,10 +1751,15 @@ static void __exit sunzilog_exit(void)
        for (i = 0; i < NUM_CHANNELS; i++) {
                struct uart_sunzilog_port *up = &sunzilog_port_table[i];
 
-               if (ZS_IS_KEYB(up) || ZS_IS_MOUSE(up))
-                       continue;
-
-               uart_remove_one_port(&sunzilog_reg, &up->port);
+               if (ZS_IS_KEYB(up) || ZS_IS_MOUSE(up)) {
+#ifdef CONFIG_SERIO
+                       if (up->serio) {
+                               serio_unregister_port(up->serio);
+                               up->serio = NULL;
+                       }
+#endif
+               } else
+                       uart_remove_one_port(&sunzilog_reg, &up->port);
        }
 
        uart_unregister_driver(&sunzilog_reg);