jsm: adding EEH handlers
[safe/jmp/linux-2.6] / drivers / serial / ioc4_serial.c
index 0c5c96a..2e02c30 100644 (file)
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2003-2005 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (C) 2003-2006 Silicon Graphics, Inc.  All Rights Reserved.
  */
 
 
@@ -308,6 +308,8 @@ struct ioc4_serial {
 typedef void ioc4_intr_func_f(void *, uint32_t);
 typedef ioc4_intr_func_f *ioc4_intr_func_t;
 
+static unsigned int Num_of_ioc4_cards;
+
 /* defining this will get you LOTS of great debug info */
 //#define DEBUG_INTERRUPTS
 #define DPRINT_CONFIG(_x...)   ;
@@ -317,12 +319,16 @@ typedef ioc4_intr_func_f *ioc4_intr_func_t;
 #define WAKEUP_CHARS   256
 
 /* number of characters we want to transmit to the lower level at a time */
-#define IOC4_MAX_CHARS 128
+#define IOC4_MAX_CHARS 256
+#define IOC4_FIFO_CHARS        255
 
 /* Device name we're using */
-#define DEVICE_NAME    "ttyIOC"
-#define DEVICE_MAJOR 204
-#define DEVICE_MINOR 50
+#define DEVICE_NAME_RS232  "ttyIOC"
+#define DEVICE_NAME_RS422  "ttyAIOC"
+#define DEVICE_MAJOR      204
+#define DEVICE_MINOR_RS232 50
+#define DEVICE_MINOR_RS422 84
+
 
 /* register offsets */
 #define IOC4_SERIAL_OFFSET     0x300
@@ -338,10 +344,8 @@ typedef ioc4_intr_func_f *ioc4_intr_func_t;
 #define MAX_BAUD_SUPPORTED     115200
 
 /* protocol types supported */
-enum sio_proto {
-       PROTO_RS232,
-       PROTO_RS422
-};
+#define PROTO_RS232    3
+#define PROTO_RS422    7
 
 /* Notification types */
 #define N_DATA_READY   0x01
@@ -392,11 +396,17 @@ enum sio_proto {
 /*
  * This is the entry saved by the driver - one per card
  */
+
+#define UART_PORT_MIN          0
+#define UART_PORT_RS232                UART_PORT_MIN
+#define UART_PORT_RS422                1
+#define UART_PORT_COUNT                2       /* one for each mode */
+
 struct ioc4_control {
        int ic_irq;
        struct {
-               /* uart ports are allocated here */
-               struct uart_port icp_uart_port;
+               /* uart ports are allocated here - 1 for rs232, 1 for rs422 */
+               struct uart_port icp_uart_port[UART_PORT_COUNT];
                /* Handy reference material */
                struct ioc4_port *icp_port;
        } ic_port[IOC4_NUM_SERIAL_PORTS];
@@ -440,7 +450,9 @@ struct ioc4_soft {
 
 /* Local port info for each IOC4 serial ports */
 struct ioc4_port {
-       struct uart_port *ip_port;
+       struct uart_port *ip_port;      /* current active port ptr */
+       /* Ptrs for all ports */
+       struct uart_port *ip_all_ports[UART_PORT_COUNT];
        /* Back ptrs for this port */
        struct ioc4_control *ip_control;
        struct pci_dev *ip_pdev;
@@ -499,6 +511,9 @@ struct ioc4_port {
 #define DCD_ON         0x02
 #define LOWAT_WRITTEN  0x04
 #define READ_ABORTED   0x08
+#define PORT_ACTIVE    0x10
+#define PORT_INACTIVE  0       /* This is the value when "off" */
+
 
 /* Since each port has different register offsets and bitmasks
  * for everything, we'll store those that we need in tables so we
@@ -620,6 +635,23 @@ struct ring_buffer {
 static void receive_chars(struct uart_port *);
 static void handle_intr(void *arg, uint32_t sio_ir);
 
+/*
+ * port_is_active - determines if this port is currently active
+ * @port: ptr to soft struct for this port
+ * @uart_port: uart port to test for
+ */
+static inline int port_is_active(struct ioc4_port *port,
+               struct uart_port *uart_port)
+{
+       if (port) {
+               if ((port->ip_flags & PORT_ACTIVE)
+                                       && (port->ip_port == uart_port))
+                       return 1;
+       }
+       return 0;
+}
+
+
 /**
  * write_ireg - write the interrupt regs
  * @ioc4_soft: ptr to soft struct for this port
@@ -705,19 +737,33 @@ static int set_baud(struct ioc4_port *port, int baud)
 /**
  * get_ioc4_port - given a uart port, return the control structure
  * @port: uart port
+ * @set: set this port as current
  */
-static struct ioc4_port *get_ioc4_port(struct uart_port *the_port)
+static struct ioc4_port *get_ioc4_port(struct uart_port *the_port, int set)
 {
        struct ioc4_driver_data *idd = dev_get_drvdata(the_port->dev);
        struct ioc4_control *control = idd->idd_serial_data;
-       int ii;
+       struct ioc4_port *port;
+       int port_num, port_type;
 
        if (control) {
-               for ( ii = 0; ii < IOC4_NUM_SERIAL_PORTS; ii++ ) {
-                       if (!control->ic_port[ii].icp_port)
+               for ( port_num = 0; port_num < IOC4_NUM_SERIAL_PORTS;
+                                                       port_num++ ) {
+                       port = control->ic_port[port_num].icp_port;
+                       if (!port)
                                continue;
-                       if (the_port == control->ic_port[ii].icp_port->ip_port)
-                               return control->ic_port[ii].icp_port;
+                       for (port_type = UART_PORT_MIN;
+                                               port_type < UART_PORT_COUNT;
+                                               port_type++) {
+                               if (the_port == port->ip_all_ports
+                                                       [port_type]) {
+                                       /* set local copy */
+                                       if (set) {
+                                               port->ip_port = the_port;
+                                       }
+                                       return port;
+                               }
+                       }
                }
        }
        return NULL;
@@ -843,7 +889,7 @@ static int inline port_init(struct ioc4_port *port)
 
                ring_pci_addr = (unsigned long __iomem)port->ip_dma_ringbuf;
                DPRINT_CONFIG(("%s: ring_pci_addr 0x%lx\n",
-                                       __FUNCTION__, ring_pci_addr));
+                                       __func__, ring_pci_addr));
 
                writel((unsigned int)((uint64_t)ring_pci_addr >> 32), sbbr_h);
                writel((unsigned int)ring_pci_addr | IOC4_BUF_SIZE_BIT, sbbr_l);
@@ -875,7 +921,7 @@ static void handle_dma_error_intr(void *arg, uint32_t other_ir)
 {
        struct ioc4_port *port = (struct ioc4_port *)arg;
        struct hooks *hooks = port->ip_hooks;
-       unsigned int flags;
+       unsigned long flags;
 
        spin_lock_irqsave(&port->ip_lock, flags);
 
@@ -884,7 +930,7 @@ static void handle_dma_error_intr(void *arg, uint32_t other_ir)
 
        if (readl(&port->ip_mem->pci_err_addr_l.raw) & IOC4_PCI_ERR_ADDR_VLD) {
                printk(KERN_ERR
-                       "PCI error address is 0x%lx, "
+                       "PCI error address is 0x%llx, "
                                "master is serial port %c %s\n",
                     (((uint64_t)readl(&port->ip_mem->pci_err_addr_h)
                                                         << 32)
@@ -941,16 +987,16 @@ intr_connect(struct ioc4_soft *soft, int type,
  * ioc4_intr - Top level IOC4 interrupt handler.
  * @irq: irq value
  * @arg: handler arg
- * @regs: registers
  */
-static irqreturn_t ioc4_intr(int irq, void *arg, struct pt_regs *regs)
+
+static irqreturn_t ioc4_intr(int irq, void *arg)
 {
        struct ioc4_soft *soft;
        uint32_t this_ir, this_mir;
        int xx, num_intrs = 0;
        int intr_type;
        int handled = 0;
-       struct ioc4_intr_info *ii;
+       struct ioc4_intr_info *intr_info;
 
        soft = arg;
        for (intr_type = 0; intr_type < IOC4_NUM_INTR_TYPES; intr_type++) {
@@ -963,39 +1009,26 @@ static irqreturn_t ioc4_intr(int irq, void *arg, struct pt_regs *regs)
                 * which interrupt bits are set.
                 */
                for (xx = 0; xx < num_intrs; xx++) {
-                       ii = &soft->is_intr_type[intr_type].is_intr_info[xx];
-                       if ((this_mir = this_ir & ii->sd_bits)) {
+                       intr_info = &soft->is_intr_type[intr_type].is_intr_info[xx];
+                       if ((this_mir = this_ir & intr_info->sd_bits)) {
                                /* Disable owned interrupts, call handler */
                                handled++;
-                               write_ireg(soft, ii->sd_bits, IOC4_W_IEC,
+                               write_ireg(soft, intr_info->sd_bits, IOC4_W_IEC,
                                                                intr_type);
-                               ii->sd_intr(ii->sd_info, this_mir);
+                               intr_info->sd_intr(intr_info->sd_info, this_mir);
                                this_ir &= ~this_mir;
                        }
                }
-               if (this_ir) {
-                       printk(KERN_ERR
-                              "unknown IOC4 %s interrupt 0x%x, sio_ir = 0x%x,"
-                               " sio_ies = 0x%x, other_ir = 0x%x :"
-                               "other_ies = 0x%x\n",
-                              (intr_type == IOC4_SIO_INTR_TYPE) ? "sio" :
-                              "other", this_ir,
-                              readl(&soft->is_ioc4_misc_addr->sio_ir.raw),
-                              readl(&soft->is_ioc4_misc_addr->sio_ies.raw),
-                              readl(&soft->is_ioc4_misc_addr->other_ir.raw),
-                              readl(&soft->is_ioc4_misc_addr->other_ies.raw));
-               }
        }
 #ifdef DEBUG_INTERRUPTS
        {
                struct ioc4_misc_regs __iomem *mem = soft->is_ioc4_misc_addr;
-               spinlock_t *lp = &soft->is_ir_lock;
                unsigned long flag;
 
                spin_lock_irqsave(&soft->is_ir_lock, flag);
                printk ("%s : %d : mem 0x%p sio_ir 0x%x sio_ies 0x%x "
                                "other_ir 0x%x other_ies 0x%x mask 0x%x\n",
-                    __FUNCTION__, __LINE__,
+                    __func__, __LINE__,
                     (void *)mem, readl(&mem->sio_ir.raw),
                     readl(&mem->sio_ies.raw),
                     readl(&mem->other_ir.raw),
@@ -1043,13 +1076,13 @@ static int inline ioc4_attach_local(struct ioc4_driver_data *idd)
        /* Create port structures for each port */
        for (port_number = 0; port_number < IOC4_NUM_SERIAL_PORTS;
                                                        port_number++) {
-               port = kmalloc(sizeof(struct ioc4_port), GFP_KERNEL);
+               port = kzalloc(sizeof(struct ioc4_port), GFP_KERNEL);
                if (!port) {
                        printk(KERN_WARNING
                                "IOC4 serial memory not available for port\n");
                        return -ENOMEM;
                }
-               memset(port, 0, sizeof(struct ioc4_port));
+               spin_lock_init(&port->ip_lock);
 
                /* we need to remember the previous ones, to point back to
                 * them farther down - setting up the ring buffers.
@@ -1122,14 +1155,14 @@ static int inline ioc4_attach_local(struct ioc4_driver_data *idd)
                                (TOTAL_RING_BUF_SIZE - 1)) == 0));
                        DPRINT_CONFIG(("%s : ip_cpu_ringbuf 0x%p "
                                                "ip_dma_ringbuf 0x%p\n",
-                                       __FUNCTION__,
+                                       __func__,
                                        (void *)port->ip_cpu_ringbuf,
                                        (void *)port->ip_dma_ringbuf));
                        port->ip_inring = RING(port, RX_0_OR_2);
                        port->ip_outring = RING(port, TX_0_OR_2);
                }
                DPRINT_CONFIG(("%s : port %d [addr 0x%p] control 0x%p",
-                               __FUNCTION__,
+                               __func__,
                                port_number, (void *)port, (void *)control));
                DPRINT_CONFIG((" ip_serial_regs 0x%p ip_uart_regs 0x%p\n",
                                (void *)port->ip_serial_regs,
@@ -1140,7 +1173,7 @@ static int inline ioc4_attach_local(struct ioc4_driver_data *idd)
 
                DPRINT_CONFIG(("%s: port_number %d port 0x%p inring 0x%p "
                                                "outring 0x%p\n",
-                               __FUNCTION__,
+                               __func__,
                                port_number, (void *)port,
                                (void *)port->ip_inring,
                                (void *)port->ip_outring));
@@ -1185,7 +1218,7 @@ static inline int local_open(struct ioc4_port *port)
 {
        int spiniter = 0;
 
-       port->ip_flags = 0;
+       port->ip_flags = PORT_ACTIVE;
 
        /* Pause the DMA interface if necessary */
        if (port->ip_sscr & IOC4_SSCR_DMA_EN) {
@@ -1195,6 +1228,7 @@ static inline int local_open(struct ioc4_port *port)
                                & IOC4_SSCR_PAUSE_STATE) == 0) {
                        spiniter++;
                        if (spiniter > MAXITER) {
+                               port->ip_flags = PORT_INACTIVE;
                                return -1;
                        }
                }
@@ -1283,7 +1317,7 @@ config_port(struct ioc4_port *port,
        int spiniter = 0;
 
        DPRINT_CONFIG(("%s: baud %d byte_size %d stop %d parenb %d parodd %d\n",
-               __FUNCTION__, baud, byte_size, stop_bits, parenb, parodd));
+               __func__, baud, byte_size, stop_bits, parenb, parodd));
 
        if (set_baud(port, baud))
                return 1;
@@ -1514,14 +1548,13 @@ static int set_notification(struct ioc4_port *port, int mask, int set_on)
 /**
  * set_mcr - set the master control reg
  * @the_port: port to use
- * @set: set ?
  * @mask1: mcr mask
  * @mask2: shadow mask
  */
-static inline int set_mcr(struct uart_port *the_port, int set,
+static inline int set_mcr(struct uart_port *the_port,
                int mask1, int mask2)
 {
-       struct ioc4_port *port = get_ioc4_port(the_port);
+       struct ioc4_port *port = get_ioc4_port(the_port, 0);
        uint32_t shadow;
        int spiniter = 0;
        char mcr;
@@ -1544,13 +1577,9 @@ static inline int set_mcr(struct uart_port *the_port, int set,
        mcr = (shadow & 0xff000000) >> 24;
 
        /* Set new value */
-       if (set) {
-               mcr |= mask1;
-               shadow |= mask2;
-       } else {
-               mcr &= ~mask1;
-               shadow &= ~mask2;
-       }
+       mcr |= mask1;
+       shadow |= mask2;
+
        writeb(mcr, &port->ip_uart_regs->i4u_mcr);
        writel(shadow, &port->ip_serial_regs->shadow);
 
@@ -1566,7 +1595,7 @@ static inline int set_mcr(struct uart_port *the_port, int set,
  * @port: port to use
  * @proto: protocol to use
  */
-static int ioc4_set_proto(struct ioc4_port *port, enum sio_proto proto)
+static int ioc4_set_proto(struct ioc4_port *port, int proto)
 {
        struct hooks *hooks = port->ip_hooks;
 
@@ -1597,26 +1626,26 @@ static void transmit_chars(struct uart_port *the_port)
        int result;
        char *start;
        struct tty_struct *tty;
-       struct ioc4_port *port = get_ioc4_port(the_port);
-       struct uart_info *info;
+       struct ioc4_port *port = get_ioc4_port(the_port, 0);
+       struct uart_state *state;
 
        if (!the_port)
                return;
        if (!port)
                return;
 
-       info = the_port->info;
-       tty = info->tty;
+       state = the_port->state;
+       tty = state->port.tty;
 
-       if (uart_circ_empty(&info->xmit) || uart_tx_stopped(the_port)) {
+       if (uart_circ_empty(&state->xmit) || uart_tx_stopped(the_port)) {
                /* Nothing to do or hw stopped */
                set_notification(port, N_ALL_OUTPUT, 0);
                return;
        }
 
-       head = info->xmit.head;
-       tail = info->xmit.tail;
-       start = (char *)&info->xmit.buf[tail];
+       head = state->xmit.head;
+       tail = state->xmit.tail;
+       start = (char *)&state->xmit.buf[tail];
 
        /* write out all the data or until the end of the buffer */
        xmit_count = (head < tail) ? (UART_XMIT_SIZE - tail) : (head - tail);
@@ -1629,14 +1658,14 @@ static void transmit_chars(struct uart_port *the_port)
                        /* advance the pointers */
                        tail += result;
                        tail &= UART_XMIT_SIZE - 1;
-                       info->xmit.tail = tail;
-                       start = (char *)&info->xmit.buf[tail];
+                       state->xmit.tail = tail;
+                       start = (char *)&state->xmit.buf[tail];
                }
        }
-       if (uart_circ_chars_pending(&info->xmit) < WAKEUP_CHARS)
+       if (uart_circ_chars_pending(&state->xmit) < WAKEUP_CHARS)
                uart_write_wakeup(the_port);
 
-       if (uart_circ_empty(&info->xmit)) {
+       if (uart_circ_empty(&state->xmit)) {
                set_notification(port, N_OUTPUT_LOWAT, 0);
        } else {
                set_notification(port, N_OUTPUT_LOWAT, 1);
@@ -1651,13 +1680,13 @@ static void transmit_chars(struct uart_port *the_port)
  */
 static void
 ioc4_change_speed(struct uart_port *the_port,
-                 struct termios *new_termios, struct termios *old_termios)
+                 struct ktermios *new_termios, struct ktermios *old_termios)
 {
-       struct ioc4_port *port = get_ioc4_port(the_port);
+       struct ioc4_port *port = get_ioc4_port(the_port, 0);
        int baud, bits;
        unsigned cflag;
        int new_parity = 0, new_parity_enable = 0, new_stop = 0, new_data = 8;
-       struct uart_info *info = the_port->info;
+       struct uart_state *state = the_port->state;
 
        cflag = new_termios->c_cflag;
 
@@ -1696,25 +1725,27 @@ ioc4_change_speed(struct uart_port *the_port,
        }
        baud = uart_get_baud_rate(the_port, new_termios, old_termios,
                                MIN_BAUD_SUPPORTED, MAX_BAUD_SUPPORTED);
-       DPRINT_CONFIG(("%s: returned baud %d\n", __FUNCTION__, baud));
+       DPRINT_CONFIG(("%s: returned baud %d\n", __func__, baud));
 
        /* default is 9600 */
        if (!baud)
                baud = 9600;
 
        if (!the_port->fifosize)
-               the_port->fifosize = IOC4_MAX_CHARS;
+               the_port->fifosize = IOC4_FIFO_CHARS;
        the_port->timeout = ((the_port->fifosize * HZ * bits) / (baud / 10));
        the_port->timeout += HZ / 50;   /* Add .02 seconds of slop */
 
        the_port->ignore_status_mask = N_ALL_INPUT;
 
-       if (I_IGNPAR(info->tty))
+       state->port.tty->low_latency = 1;
+
+       if (I_IGNPAR(state->port.tty))
                the_port->ignore_status_mask &= ~(N_PARITY_ERROR
                                                | N_FRAMING_ERROR);
-       if (I_IGNBRK(info->tty)) {
+       if (I_IGNBRK(state->port.tty)) {
                the_port->ignore_status_mask &= ~N_BREAK;
-               if (I_IGNPAR(info->tty))
+               if (I_IGNPAR(state->port.tty))
                        the_port->ignore_status_mask &= ~N_OVERRUN_ERROR;
        }
        if (!(cflag & CREAD)) {
@@ -1723,11 +1754,9 @@ ioc4_change_speed(struct uart_port *the_port,
        }
 
        if (cflag & CRTSCTS) {
-               info->flags |= ASYNC_CTS_FLOW;
                port->ip_sscr |= IOC4_SSCR_HFC_EN;
        }
        else {
-               info->flags &= ~ASYNC_CTS_FLOW;
                port->ip_sscr &= ~IOC4_SSCR_HFC_EN;
        }
        writel(port->ip_sscr, &port->ip_serial_regs->sscr);
@@ -1736,7 +1765,7 @@ ioc4_change_speed(struct uart_port *the_port,
        DPRINT_CONFIG(("%s : port 0x%p cflag 0%o "
                "config_port(baud %d data %d stop %d p enable %d parity %d),"
                " notification 0x%x\n",
-            __FUNCTION__, (void *)port, cflag, baud, new_data, new_stop,
+            __func__, (void *)port, cflag, baud, new_data, new_stop,
             new_parity_enable, new_parity, the_port->ignore_status_mask));
 
        if ((config_port(port, baud,            /* baud */
@@ -1754,52 +1783,43 @@ ioc4_change_speed(struct uart_port *the_port,
  */
 static inline int ic4_startup_local(struct uart_port *the_port)
 {
-       int retval = 0;
        struct ioc4_port *port;
-       struct uart_info *info;
+       struct uart_state *state;
 
        if (!the_port)
                return -1;
 
-       port = get_ioc4_port(the_port);
+       port = get_ioc4_port(the_port, 0);
        if (!port)
                return -1;
 
-       info = the_port->info;
-       if (info->flags & UIF_INITIALIZED) {
-               return retval;
-       }
+       state = the_port->state;
 
-       if (info->tty) {
-               set_bit(TTY_IO_ERROR, &info->tty->flags);
-               clear_bit(TTY_IO_ERROR, &info->tty->flags);
-               if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
-                       info->tty->alt_speed = 57600;
-               if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
-                       info->tty->alt_speed = 115200;
-               if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
-                       info->tty->alt_speed = 230400;
-               if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
-                       info->tty->alt_speed = 460800;
-       }
        local_open(port);
 
+       /* set the protocol - mapbase has the port type */
+       ioc4_set_proto(port, the_port->mapbase);
+
        /* set the speed of the serial port */
-       ioc4_change_speed(the_port, info->tty->termios, (struct termios *)0);
+       ioc4_change_speed(the_port, state->port.tty->termios,
+                         (struct ktermios *)0);
 
-       info->flags |= UIF_INITIALIZED;
        return 0;
 }
 
 /*
  * ioc4_cb_output_lowat - called when the output low water mark is hit
- * @port: port to output
+ * @the_port: port to output
  */
-static void ioc4_cb_output_lowat(struct ioc4_port *port)
+static void ioc4_cb_output_lowat(struct uart_port *the_port)
 {
+       unsigned long pflags;
+
        /* ip_lock is set on the call here */
-       if (port->ip_port) {
-               transmit_chars(port->ip_port);
+       if (the_port) {
+               spin_lock_irqsave(&the_port->lock, pflags);
+               transmit_chars(the_port);
+               spin_unlock_irqrestore(&the_port->lock, pflags);
        }
 }
 
@@ -1814,7 +1834,7 @@ static void handle_intr(void *arg, uint32_t sio_ir)
        struct ioc4_port *port = (struct ioc4_port *)arg;
        struct hooks *hooks = port->ip_hooks;
        unsigned int rx_high_rd_aborted = 0;
-       unsigned int flags;
+       unsigned long flags;
        struct uart_port *the_port;
        int loop_counter;
 
@@ -1862,7 +1882,7 @@ static void handle_intr(void *arg, uint32_t sio_ir)
                                the_port = port->ip_port;
                                the_port->icount.dcd = 1;
                                wake_up_interruptible
-                                           (&the_port-> info->delta_msr_wait);
+                                           (&the_port->state->port.delta_msr_wait);
                        } else if ((port->ip_notify & N_DDCD)
                                        && !(shadow & IOC4_SHADOW_DCD)) {
                                /* Flag delta DCD/no DCD */
@@ -1884,7 +1904,7 @@ static void handle_intr(void *arg, uint32_t sio_ir)
                                the_port->icount.cts =
                                        (shadow & IOC4_SHADOW_CTS) ? 1 : 0;
                                wake_up_interruptible
-                                       (&the_port->info->delta_msr_wait);
+                                       (&the_port->state->port.delta_msr_wait);
                        }
                }
 
@@ -1944,7 +1964,7 @@ static void handle_intr(void *arg, uint32_t sio_ir)
                                        &port->ip_mem->sio_ir.raw);
 
                        if (port->ip_notify & N_OUTPUT_LOWAT)
-                               ioc4_cb_output_lowat(port);
+                               ioc4_cb_output_lowat(port->ip_port);
                }
 
                /* Handle tx_mt.  Must come after tx_explicit.  */
@@ -1957,7 +1977,7 @@ static void handle_intr(void *arg, uint32_t sio_ir)
                         * So send the notification now.
                         */
                        if (port->ip_notify & N_OUTPUT_LOWAT) {
-                               ioc4_cb_output_lowat(port);
+                               ioc4_cb_output_lowat(port->ip_port);
 
                                /* We need to reload the sio_ir since the lowat
                                 * call may have caused another write to occur,
@@ -2044,7 +2064,7 @@ static inline int do_read(struct uart_port *the_port, unsigned char *buf,
                                int len)
 {
        int prod_ptr, cons_ptr, total;
-       struct ioc4_port *port = get_ioc4_port(the_port);
+       struct ioc4_port *port = get_ioc4_port(the_port, 0);
        struct ring *inring;
        struct ring_entry *entry;
        struct hooks *hooks = port->ip_hooks;
@@ -2076,8 +2096,7 @@ static inline int do_read(struct uart_port *the_port, unsigned char *buf,
         * available data as long as it returns some.
         */
        /* Re-arm the timer */
-       writel(port->ip_rx_cons | IOC4_SRCIR_ARM,
-                       &port->ip_serial_regs->srcir);
+       writel(port->ip_rx_cons | IOC4_SRCIR_ARM, &port->ip_serial_regs->srcir);
 
        prod_ptr = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK;
        cons_ptr = port->ip_rx_cons;
@@ -2217,8 +2236,8 @@ static inline int do_read(struct uart_port *the_port, unsigned char *buf,
                                                   && port->ip_port) {
                                                the_port->icount.dcd = 0;
                                                wake_up_interruptible
-                                                   (&the_port->info->
-                                                       delta_msr_wait);
+                                                   (&the_port->state->
+                                                       port.delta_msr_wait);
                                        }
 
                                        /* If we had any data to return, we
@@ -2311,6 +2330,7 @@ static inline int do_read(struct uart_port *the_port, unsigned char *buf,
        }
        return total;
 }
+
 /**
  * receive_chars - upper level read. Called with ip_lock.
  * @the_port: port to read from
@@ -2319,34 +2339,33 @@ static void receive_chars(struct uart_port *the_port)
 {
        struct tty_struct *tty;
        unsigned char ch[IOC4_MAX_CHARS];
-       int read_count, request_count;
+       int read_count, request_count = IOC4_MAX_CHARS;
        struct uart_icount *icount;
-       struct uart_info *info = the_port->info;
+       struct uart_state *state = the_port->state;
+       unsigned long pflags;
 
        /* Make sure all the pointers are "good" ones */
-       if (!info)
+       if (!state)
                return;
-       if (!info->tty)
+       if (!state->port.tty)
                return;
 
-       tty = info->tty;
+       spin_lock_irqsave(&the_port->lock, pflags);
+       tty = state->port.tty;
 
-       request_count = TTY_FLIPBUF_SIZE - tty->flip.count - 1;
+       request_count = tty_buffer_request_room(tty, IOC4_MAX_CHARS);
 
        if (request_count > 0) {
-               if (request_count > IOC4_MAX_CHARS - 2)
-                       request_count = IOC4_MAX_CHARS - 2;
                icount = &the_port->icount;
                read_count = do_read(the_port, ch, request_count);
                if (read_count > 0) {
-                       memcpy(tty->flip.char_buf_ptr, ch, read_count);
-                       memset(tty->flip.flag_buf_ptr, TTY_NORMAL, read_count);
-                       tty->flip.char_buf_ptr += read_count;
-                       tty->flip.flag_buf_ptr += read_count;
-                       tty->flip.count += read_count;
+                       tty_insert_flip_string(tty, ch, read_count);
                        icount->rx += read_count;
                }
        }
+
+       spin_unlock_irqrestore(&the_port->lock, pflags);
+
        tty_flip_buffer_push(tty);
 }
 
@@ -2357,17 +2376,27 @@ static void receive_chars(struct uart_port *the_port)
  */
 static const char *ic4_type(struct uart_port *the_port)
 {
-       return "SGI IOC4 Serial";
+       if (the_port->mapbase == PROTO_RS232)
+               return "SGI IOC4 Serial [rs232]";
+       else
+               return "SGI IOC4 Serial [rs422]";
 }
 
 /**
- * ic4_tx_empty - Is the transmitter empty?  We pretend we're always empty
- * @port: Port to operate on (we ignore since we always return 1)
+ * ic4_tx_empty - Is the transmitter empty?
+ * @port: Port to operate on
  *
  */
 static unsigned int ic4_tx_empty(struct uart_port *the_port)
 {
-       return 1;
+       struct ioc4_port *port = get_ioc4_port(the_port, 0);
+       unsigned int ret = 0;
+
+       if (port_is_active(port, the_port)) {
+               if (readl(&port->ip_serial_regs->shadow) & IOC4_SHADOW_TEMT)
+                       ret = TIOCSER_TEMT;
+       }
+       return ret;
 }
 
 /**
@@ -2377,6 +2406,10 @@ static unsigned int ic4_tx_empty(struct uart_port *the_port)
  */
 static void ic4_stop_tx(struct uart_port *the_port)
 {
+       struct ioc4_port *port = get_ioc4_port(the_port, 0);
+
+       if (port_is_active(port, the_port))
+               set_notification(port, N_OUTPUT_LOWAT, 0);
 }
 
 /**
@@ -2397,26 +2430,24 @@ static void ic4_shutdown(struct uart_port *the_port)
 {
        unsigned long port_flags;
        struct ioc4_port *port;
-       struct uart_info *info;
+       struct uart_state *state;
 
-       port = get_ioc4_port(the_port);
+       port = get_ioc4_port(the_port, 0);
        if (!port)
                return;
 
-       info = the_port->info;
+       state = the_port->state;
+       port->ip_port = NULL;
 
-       if (!(info->flags & UIF_INITIALIZED))
-               return;
-
-       wake_up_interruptible(&info->delta_msr_wait);
+       wake_up_interruptible(&state->port.delta_msr_wait);
 
-       if (info->tty)
-               set_bit(TTY_IO_ERROR, &info->tty->flags);
+       if (state->port.tty)
+               set_bit(TTY_IO_ERROR, &state->port.tty->flags);
 
-       spin_lock_irqsave(&port->ip_lock, port_flags);
+       spin_lock_irqsave(&the_port->lock, port_flags);
        set_notification(port, N_ALL, 0);
-       info->flags &= ~UIF_INITIALIZED;
-       spin_unlock_irqrestore(&port->ip_lock, port_flags);
+       port->ip_flags = PORT_INACTIVE;
+       spin_unlock_irqrestore(&the_port->lock, port_flags);
 }
 
 /**
@@ -2428,6 +2459,11 @@ static void ic4_shutdown(struct uart_port *the_port)
 static void ic4_set_mctrl(struct uart_port *the_port, unsigned int mctrl)
 {
        unsigned char mcr = 0;
+       struct ioc4_port *port;
+
+       port = get_ioc4_port(the_port, 0);
+       if (!port_is_active(port, the_port))
+               return;
 
        if (mctrl & TIOCM_RTS)
                mcr |= UART_MCR_RTS;
@@ -2440,7 +2476,7 @@ static void ic4_set_mctrl(struct uart_port *the_port, unsigned int mctrl)
        if (mctrl & TIOCM_LOOP)
                mcr |= UART_MCR_LOOP;
 
-       set_mcr(the_port, 1, mcr, IOC4_SHADOW_DTR);
+       set_mcr(the_port, mcr, IOC4_SHADOW_DTR);
 }
 
 /**
@@ -2450,11 +2486,11 @@ static void ic4_set_mctrl(struct uart_port *the_port, unsigned int mctrl)
  */
 static unsigned int ic4_get_mctrl(struct uart_port *the_port)
 {
-       struct ioc4_port *port = get_ioc4_port(the_port);
+       struct ioc4_port *port = get_ioc4_port(the_port, 0);
        uint32_t shadow;
        unsigned int ret = 0;
 
-       if (!port)
+       if (!port_is_active(port, the_port))
                return 0;
 
        shadow = readl(&port->ip_serial_regs->shadow);
@@ -2474,13 +2510,11 @@ static unsigned int ic4_get_mctrl(struct uart_port *the_port)
  */
 static void ic4_start_tx(struct uart_port *the_port)
 {
-       struct ioc4_port *port = get_ioc4_port(the_port);
-       unsigned long flags;
+       struct ioc4_port *port = get_ioc4_port(the_port, 0);
 
-       if (port) {
-               spin_lock_irqsave(&port->ip_lock, flags);
-               transmit_chars(the_port);
-               spin_unlock_irqrestore(&port->ip_lock, flags);
+       if (port_is_active(port, the_port)) {
+               set_notification(port, N_OUTPUT_LOWAT, 1);
+               enable_intrs(port, port->ip_hooks->intr_tx_mt);
        }
 }
 
@@ -2495,7 +2529,7 @@ static void ic4_break_ctl(struct uart_port *the_port, int break_state)
 }
 
 /**
- * ic4_startup - Start up the serial port - always return 0 (We're always on)
+ * ic4_startup - Start up the serial port
  * @port: Port to operate on
  *
  */
@@ -2504,27 +2538,26 @@ static int ic4_startup(struct uart_port *the_port)
        int retval;
        struct ioc4_port *port;
        struct ioc4_control *control;
-       struct uart_info *info;
+       struct uart_state *state;
        unsigned long port_flags;
 
-       if (!the_port) {
+       if (!the_port)
                return -ENODEV;
-       }
-       port = get_ioc4_port(the_port);
-       if (!port) {
+       port = get_ioc4_port(the_port, 1);
+       if (!port)
                return -ENODEV;
-       }
-       info = the_port->info;
+       state = the_port->state;
 
        control = port->ip_control;
        if (!control) {
+               port->ip_port = NULL;
                return -ENODEV;
        }
 
        /* Start up the serial port */
-       spin_lock_irqsave(&port->ip_lock, port_flags);
+       spin_lock_irqsave(&the_port->lock, port_flags);
        retval = ic4_startup_local(the_port);
-       spin_unlock_irqrestore(&port->ip_lock, port_flags);
+       spin_unlock_irqrestore(&the_port->lock, port_flags);
        return retval;
 }
 
@@ -2537,14 +2570,13 @@ static int ic4_startup(struct uart_port *the_port)
  */
 static void
 ic4_set_termios(struct uart_port *the_port,
-               struct termios *termios, struct termios *old_termios)
+               struct ktermios *termios, struct ktermios *old_termios)
 {
-       struct ioc4_port *port = get_ioc4_port(the_port);
        unsigned long port_flags;
 
-       spin_lock_irqsave(&port->ip_lock, port_flags);
+       spin_lock_irqsave(&the_port->lock, port_flags);
        ioc4_change_speed(the_port, termios, old_termios);
-       spin_unlock_irqrestore(&port->ip_lock, port_flags);
+       spin_unlock_irqrestore(&the_port->lock, port_flags);
 }
 
 /**
@@ -2580,66 +2612,153 @@ static struct uart_ops ioc4_ops = {
  * Boot-time initialization code
  */
 
-static struct uart_driver ioc4_uart = {
+static struct uart_driver ioc4_uart_rs232 = {
        .owner          = THIS_MODULE,
-       .driver_name    = "ioc4_serial",
-       .dev_name       = DEVICE_NAME,
+       .driver_name    = "ioc4_serial_rs232",
+       .dev_name       = DEVICE_NAME_RS232,
        .major          = DEVICE_MAJOR,
-       .minor          = DEVICE_MINOR,
+       .minor          = DEVICE_MINOR_RS232,
        .nr             = IOC4_NUM_CARDS * IOC4_NUM_SERIAL_PORTS,
 };
 
+static struct uart_driver ioc4_uart_rs422 = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "ioc4_serial_rs422",
+       .dev_name       = DEVICE_NAME_RS422,
+       .major          = DEVICE_MAJOR,
+       .minor          = DEVICE_MINOR_RS422,
+       .nr             = IOC4_NUM_CARDS * IOC4_NUM_SERIAL_PORTS,
+};
+
+
 /**
- * ioc4_serial_core_attach - register with serial core
+ * ioc4_serial_remove_one - detach function
+ *
+ * @idd: IOC4 master module data for this IOC4
+ */
+
+static int ioc4_serial_remove_one(struct ioc4_driver_data *idd)
+{
+       int port_num, port_type;
+       struct ioc4_control *control;
+       struct uart_port *the_port;
+       struct ioc4_port *port;
+       struct ioc4_soft *soft;
+
+       /* If serial driver did not attach, don't try to detach */
+       control = idd->idd_serial_data;
+       if (!control)
+               return 0;
+
+       for (port_num = 0; port_num < IOC4_NUM_SERIAL_PORTS; port_num++) {
+               for (port_type = UART_PORT_MIN;
+                                       port_type < UART_PORT_COUNT;
+                                       port_type++) {
+                       the_port = &control->ic_port[port_num].icp_uart_port
+                                                       [port_type];
+                       if (the_port) {
+                               switch (port_type) {
+                               case UART_PORT_RS422:
+                                       uart_remove_one_port(&ioc4_uart_rs422,
+                                                       the_port);
+                                       break;
+                               default:
+                               case UART_PORT_RS232:
+                                       uart_remove_one_port(&ioc4_uart_rs232,
+                                                       the_port);
+                                       break;
+                               }
+                       }
+               }
+               port = control->ic_port[port_num].icp_port;
+               /* we allocate in pairs */
+               if (!(port_num & 1) && port) {
+                       pci_free_consistent(port->ip_pdev,
+                                       TOTAL_RING_BUF_SIZE,
+                                       port->ip_cpu_ringbuf,
+                                       port->ip_dma_ringbuf);
+                       kfree(port);
+               }
+       }
+       soft = control->ic_soft;
+       if (soft) {
+               free_irq(control->ic_irq, soft);
+               if (soft->is_ioc4_serial_addr) {
+                       iounmap(soft->is_ioc4_serial_addr);
+                       release_mem_region((unsigned long)
+                            soft->is_ioc4_serial_addr,
+                               sizeof(struct ioc4_serial));
+               }
+               kfree(soft);
+       }
+       kfree(control);
+       idd->idd_serial_data = NULL;
+
+       return 0;
+}
+
+
+/**
+ * ioc4_serial_core_attach_rs232 - register with serial core
  *             This is done during pci probing
  * @pdev: handle for this card
  */
 static inline int
-ioc4_serial_core_attach(struct pci_dev *pdev)
+ioc4_serial_core_attach(struct pci_dev *pdev, int port_type)
 {
        struct ioc4_port *port;
        struct uart_port *the_port;
        struct ioc4_driver_data *idd = pci_get_drvdata(pdev);
        struct ioc4_control *control = idd->idd_serial_data;
-       int ii;
+       int port_num;
+       int port_type_idx;
+       struct uart_driver *u_driver;
+
 
        DPRINT_CONFIG(("%s: attach pdev 0x%p - control 0x%p\n",
-                       __FUNCTION__, pdev, (void *)control));
+                       __func__, pdev, (void *)control));
 
        if (!control)
                return -ENODEV;
 
+       port_type_idx = (port_type == PROTO_RS232) ? UART_PORT_RS232
+                                               : UART_PORT_RS422;
+
+       u_driver = (port_type == PROTO_RS232)   ? &ioc4_uart_rs232
+                                               : &ioc4_uart_rs422;
+
        /* once around for each port on this card */
-       for (ii = 0; ii < IOC4_NUM_SERIAL_PORTS; ii++) {
-               the_port = &control->ic_port[ii].icp_uart_port;
-               port = control->ic_port[ii].icp_port;
-               port->ip_port = the_port;
+       for (port_num = 0; port_num < IOC4_NUM_SERIAL_PORTS; port_num++) {
+               the_port = &control->ic_port[port_num].icp_uart_port
+                                                       [port_type_idx];
+               port = control->ic_port[port_num].icp_port;
+               port->ip_all_ports[port_type_idx] = the_port;
 
-               DPRINT_CONFIG(("%s: attach the_port 0x%p / port 0x%p\n",
-                               __FUNCTION__, (void *)the_port,
-                               (void *)port));
+               DPRINT_CONFIG(("%s: attach the_port 0x%p / port 0x%p : type %s\n",
+                               __func__, (void *)the_port,
+                               (void *)port,
+                               port_type == PROTO_RS232 ? "rs232" : "rs422"));
 
-               spin_lock_init(&the_port->lock);
                /* membase, iobase and mapbase just need to be non-0 */
                the_port->membase = (unsigned char __iomem *)1;
-               the_port->line = the_port->iobase = ii;
-               the_port->mapbase = 1;
+               the_port->iobase = (pdev->bus->number << 16) |  port_num;
+               the_port->line = (Num_of_ioc4_cards << 2) | port_num;
+               the_port->mapbase = port_type;
                the_port->type = PORT_16550A;
-               the_port->fifosize = IOC4_MAX_CHARS;
+               the_port->fifosize = IOC4_FIFO_CHARS;
                the_port->ops = &ioc4_ops;
                the_port->irq = control->ic_irq;
                the_port->dev = &pdev->dev;
-               if (uart_add_one_port(&ioc4_uart, the_port) < 0) {
+               spin_lock_init(&the_port->lock);
+               if (uart_add_one_port(u_driver, the_port) < 0) {
                        printk(KERN_WARNING
-                                      "%s: unable to add port %d\n",
-                                      __FUNCTION__, the_port->line);
+                          "%s: unable to add port %d bus %d\n",
+                              __func__, the_port->line, pdev->bus->number);
                } else {
                        DPRINT_CONFIG(
-                                   ("IOC4 serial driver port %d irq = %d\n",
-                                      the_port->line, the_port->irq));
+                           ("IOC4 serial port %d irq = %d, bus %d\n",
+                              the_port->line, the_port->irq, pdev->bus->number));
                }
-               /* all ports are rs232 for now */
-               ioc4_set_proto(port, PROTO_RS232);
        }
        return 0;
 }
@@ -2659,12 +2778,19 @@ ioc4_serial_attach_one(struct ioc4_driver_data *idd)
        int ret = 0;
 
 
-       DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __FUNCTION__, idd->idd_pdev, idd->idd_pci_id));
+       DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __func__, idd->idd_pdev,
+                                                       idd->idd_pci_id));
+
+       /* PCI-RT does not bring out serial connections.
+        * Do not attach to this particular IOC4.
+        */
+       if (idd->idd_variant == IOC4_VARIANT_PCI_RT)
+               return 0;
 
        /* request serial registers */
        tmp_addr1 = idd->idd_bar0 + IOC4_SERIAL_OFFSET;
 
-       if (!request_region(tmp_addr1, sizeof(struct ioc4_serial),
+       if (!request_mem_region(tmp_addr1, sizeof(struct ioc4_serial),
                                        "sioc4_uart")) {
                printk(KERN_WARNING
                        "ioc4 (%p): unable to get request region for "
@@ -2681,11 +2807,11 @@ ioc4_serial_attach_one(struct ioc4_driver_data *idd)
                goto out2;
        }
        DPRINT_CONFIG(("%s : mem 0x%p, serial 0x%p\n",
-                               __FUNCTION__, (void *)idd->idd_misc_regs, (void *)serial));
+                               __func__, (void *)idd->idd_misc_regs,
+                               (void *)serial));
 
        /* Get memory for the new card */
-       control = kmalloc(sizeof(struct ioc4_control) * IOC4_NUM_SERIAL_PORTS,
-                                               GFP_KERNEL);
+       control = kzalloc(sizeof(struct ioc4_control), GFP_KERNEL);
 
        if (!control) {
                printk(KERN_WARNING "ioc4_attach_one"
@@ -2693,11 +2819,10 @@ ioc4_serial_attach_one(struct ioc4_driver_data *idd)
                ret = -ENOMEM;
                goto out2;
        }
-       memset(control, 0, sizeof(struct ioc4_control));
        idd->idd_serial_data = control;
 
        /* Allocate the soft structure */
-       soft = kmalloc(sizeof(struct ioc4_soft), GFP_KERNEL);
+       soft = kzalloc(sizeof(struct ioc4_soft), GFP_KERNEL);
        if (!soft) {
                printk(KERN_WARNING
                       "ioc4 (%p): unable to get memory for the soft struct\n",
@@ -2705,7 +2830,6 @@ ioc4_serial_attach_one(struct ioc4_driver_data *idd)
                ret = -ENOMEM;
                goto out3;
        }
-       memset(soft, 0, sizeof(struct ioc4_soft));
 
        spin_lock_init(&soft->is_ir_lock);
        soft->is_ioc4_misc_addr = idd->idd_misc_regs;
@@ -2729,84 +2853,47 @@ ioc4_serial_attach_one(struct ioc4_driver_data *idd)
        control->ic_soft = soft;
 
        /* Hook up interrupt handler */
-       if (!request_irq(idd->idd_pdev->irq, ioc4_intr, SA_SHIRQ,
-                               "sgi-ioc4serial", (void *)soft)) {
+       if (!request_irq(idd->idd_pdev->irq, ioc4_intr, IRQF_SHARED,
+                               "sgi-ioc4serial", soft)) {
                control->ic_irq = idd->idd_pdev->irq;
        } else {
                printk(KERN_WARNING
                    "%s : request_irq fails for IRQ 0x%x\n ",
-                       __FUNCTION__, idd->idd_pdev->irq);
+                       __func__, idd->idd_pdev->irq);
        }
        ret = ioc4_attach_local(idd);
        if (ret)
                goto out4;
 
-       /* register port with the serial core */
+       /* register port with the serial core - 1 rs232, 1 rs422 */
 
-       if ((ret = ioc4_serial_core_attach(idd->idd_pdev)))
+       if ((ret = ioc4_serial_core_attach(idd->idd_pdev, PROTO_RS232)))
                goto out4;
 
+       if ((ret = ioc4_serial_core_attach(idd->idd_pdev, PROTO_RS422)))
+               goto out5;
+
+       Num_of_ioc4_cards++;
+
        return ret;
 
        /* error exits that give back resources */
+out5:
+       ioc4_serial_remove_one(idd);
 out4:
        kfree(soft);
 out3:
        kfree(control);
 out2:
-       release_region(tmp_addr1, sizeof(struct ioc4_serial));
+       if (serial)
+               iounmap(serial);
+       release_mem_region(tmp_addr1, sizeof(struct ioc4_serial));
 out1:
 
        return ret;
 }
 
 
-/**
- * ioc4_serial_remove_one - detach function
- *
- * @idd: IOC4 master module data for this IOC4
- */
-
-int ioc4_serial_remove_one(struct ioc4_driver_data *idd)
-{
-       int ii;
-       struct ioc4_control *control;
-       struct uart_port *the_port;
-       struct ioc4_port *port;
-       struct ioc4_soft *soft;
-
-       control = idd->idd_serial_data;
-
-       for (ii = 0; ii < IOC4_NUM_SERIAL_PORTS; ii++) {
-               the_port = &control->ic_port[ii].icp_uart_port;
-               if (the_port) {
-                       uart_remove_one_port(&ioc4_uart, the_port);
-               }
-               port = control->ic_port[ii].icp_port;
-               if (!(ii & 1) && port) {
-                       pci_free_consistent(port->ip_pdev,
-                                       TOTAL_RING_BUF_SIZE,
-                                       (void *)port->ip_cpu_ringbuf,
-                                       port->ip_dma_ringbuf);
-                       kfree(port);
-               }
-       }
-       soft = control->ic_soft;
-       if (soft) {
-               free_irq(control->ic_irq, (void *)soft);
-               if (soft->is_ioc4_serial_addr) {
-                       release_region((unsigned long)
-                            soft->is_ioc4_serial_addr,
-                               sizeof(struct ioc4_serial));
-               }
-               kfree(soft);
-       }
-       kfree(control);
-       idd->idd_serial_data = NULL;
-
-       return 0;
-}
-
 static struct ioc4_submodule ioc4_serial_submodule = {
        .is_name = "IOC4_serial",
        .is_owner = THIS_MODULE,
@@ -2822,10 +2909,16 @@ int ioc4_serial_init(void)
        int ret;
 
        /* register with serial core */
-       if ((ret = uart_register_driver(&ioc4_uart)) < 0) {
+       if ((ret = uart_register_driver(&ioc4_uart_rs232)) < 0) {
+               printk(KERN_WARNING
+                       "%s: Couldn't register rs232 IOC4 serial driver\n",
+                       __func__);
+               return ret;
+       }
+       if ((ret = uart_register_driver(&ioc4_uart_rs422)) < 0) {
                printk(KERN_WARNING
-                       "%s: Couldn't register IOC4 serial driver\n",
-                       __FUNCTION__);
+                       "%s: Couldn't register rs422 IOC4 serial driver\n",
+                       __func__);
                return ret;
        }
 
@@ -2836,10 +2929,11 @@ int ioc4_serial_init(void)
 static void __devexit ioc4_serial_exit(void)
 {
        ioc4_unregister_submodule(&ioc4_serial_submodule);
-       uart_unregister_driver(&ioc4_uart);
+       uart_unregister_driver(&ioc4_uart_rs232);
+       uart_unregister_driver(&ioc4_uart_rs422);
 }
 
-module_init(ioc4_serial_init);
+late_initcall(ioc4_serial_init); /* Call only after tty init is done */
 module_exit(ioc4_serial_exit);
 
 MODULE_AUTHOR("Pat Gefre - Silicon Graphics Inc. (SGI) <pfg@sgi.com>");