]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - drivers/tty/amiserial.c
TTY: amiserial, stop using serial_state->{irq,type,line}
[mirror_ubuntu-artful-kernel.git] / drivers / tty / amiserial.c
index b84c83456dccf276e135cf07e50d7063b7da8440..b182bccf3eab681b1f0f26e65ef02be62eab3fd4 100644 (file)
@@ -45,7 +45,7 @@
 
 #if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT)
 #define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \
- tty->name, (info->flags), serial_driver->refcount,info->count,tty->count,s)
+ tty->name, (info->tport.flags), serial_driver->refcount,info->count,tty->count,s)
 #else
 #define DBG_CNT(s)
 #endif
@@ -100,11 +100,10 @@ static struct tty_driver *serial_driver;
 /* number of characters left in xmit buffer before we ask for more */
 #define WAKEUP_CHARS 256
 
-static struct async_struct *IRQ_ports;
-
 static unsigned char current_ctl_bits;
 
-static void change_speed(struct async_struct *info, struct ktermios *old);
+static void change_speed(struct tty_struct *tty, struct serial_state *info,
+               struct ktermios *old);
 static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
 
 
@@ -117,7 +116,7 @@ static struct serial_state rs_table[1];
 #define serial_isroot()        (capable(CAP_SYS_ADMIN))
 
 
-static inline int serial_paranoia_check(struct async_struct *info,
+static inline int serial_paranoia_check(struct serial_state *info,
                                        char *name, const char *routine)
 {
 #ifdef SERIAL_PARANOIA_CHECK
@@ -170,7 +169,7 @@ static __inline__ void rtsdtr_ctrl(int bits)
  */
 static void rs_stop(struct tty_struct *tty)
 {
-       struct async_struct *info = tty->driver_data;
+       struct serial_state *info = tty->driver_data;
        unsigned long flags;
 
        if (serial_paranoia_check(info, tty->name, "rs_stop"))
@@ -190,7 +189,7 @@ static void rs_stop(struct tty_struct *tty)
 
 static void rs_start(struct tty_struct *tty)
 {
-       struct async_struct *info = tty->driver_data;
+       struct serial_state *info = tty->driver_data;
        unsigned long flags;
 
        if (serial_paranoia_check(info, tty->name, "rs_start"))
@@ -231,27 +230,16 @@ static void rs_start(struct tty_struct *tty)
  * -----------------------------------------------------------------------
  */
 
-/*
- * This routine is used by the interrupt handler to schedule
- * processing in the software interrupt portion of the driver.
- */
-static void rs_sched_event(struct async_struct *info,
-                          int event)
-{
-       info->event |= 1 << event;
-       tasklet_schedule(&info->tlet);
-}
-
-static void receive_chars(struct async_struct *info)
+static void receive_chars(struct serial_state *info)
 {
         int status;
        int serdatr;
-       struct tty_struct *tty = info->tty;
+       struct tty_struct *tty = info->tport.tty;
        unsigned char ch, flag;
        struct  async_icount *icount;
        int oe = 0;
 
-       icount = &info->state->icount;
+       icount = &info->icount;
 
        status = UART_LSR_DR; /* We obviously have a character! */
        serdatr = custom.serdatr;
@@ -308,7 +296,7 @@ static void receive_chars(struct async_struct *info)
            printk("handling break....");
 #endif
            flag = TTY_BREAK;
-           if (info->flags & ASYNC_SAK)
+           if (info->tport.flags & ASYNC_SAK)
              do_SAK(tty);
          } else if (status & UART_LSR_PE)
            flag = TTY_PARITY;
@@ -331,20 +319,20 @@ out:
        return;
 }
 
-static void transmit_chars(struct async_struct *info)
+static void transmit_chars(struct serial_state *info)
 {
        custom.intreq = IF_TBE;
        mb();
        if (info->x_char) {
                custom.serdat = info->x_char | 0x100;
                mb();
-               info->state->icount.tx++;
+               info->icount.tx++;
                info->x_char = 0;
                return;
        }
        if (info->xmit.head == info->xmit.tail
-           || info->tty->stopped
-           || info->tty->hw_stopped) {
+           || info->tport.tty->stopped
+           || info->tport.tty->hw_stopped) {
                info->IER &= ~UART_IER_THRI;
                custom.intena = IF_TBE;
                mb();
@@ -354,12 +342,12 @@ static void transmit_chars(struct async_struct *info)
        custom.serdat = info->xmit.buf[info->xmit.tail++] | 0x100;
        mb();
        info->xmit.tail = info->xmit.tail & (SERIAL_XMIT_SIZE-1);
-       info->state->icount.tx++;
+       info->icount.tx++;
 
        if (CIRC_CNT(info->xmit.head,
                     info->xmit.tail,
                     SERIAL_XMIT_SIZE) < WAKEUP_CHARS)
-               rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+               tty_wakeup(info->tport.tty);
 
 #ifdef SERIAL_DEBUG_INTR
        printk("THRE...");
@@ -371,8 +359,9 @@ static void transmit_chars(struct async_struct *info)
        }
 }
 
-static void check_modem_status(struct async_struct *info)
+static void check_modem_status(struct serial_state *info)
 {
+       struct tty_port *port = &info->tport;
        unsigned char status = ciab.pra & (SER_DCD | SER_CTS | SER_DSR);
        unsigned char dstatus;
        struct  async_icount *icount;
@@ -382,52 +371,52 @@ static void check_modem_status(struct async_struct *info)
        current_ctl_bits = status;
 
        if (dstatus) {
-               icount = &info->state->icount;
+               icount = &info->icount;
                /* update input line counters */
                if (dstatus & SER_DSR)
                        icount->dsr++;
                if (dstatus & SER_DCD) {
                        icount->dcd++;
 #ifdef CONFIG_HARD_PPS
-                       if ((info->flags & ASYNC_HARDPPS_CD) &&
+                       if ((port->flags & ASYNC_HARDPPS_CD) &&
                            !(status & SER_DCD))
                                hardpps();
 #endif
                }
                if (dstatus & SER_CTS)
                        icount->cts++;
-               wake_up_interruptible(&info->delta_msr_wait);
+               wake_up_interruptible(&port->delta_msr_wait);
        }
 
-       if ((info->flags & ASYNC_CHECK_CD) && (dstatus & SER_DCD)) {
+       if ((port->flags & ASYNC_CHECK_CD) && (dstatus & SER_DCD)) {
 #if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
                printk("ttyS%d CD now %s...", info->line,
                       (!(status & SER_DCD)) ? "on" : "off");
 #endif
                if (!(status & SER_DCD))
-                       wake_up_interruptible(&info->open_wait);
+                       wake_up_interruptible(&port->open_wait);
                else {
 #ifdef SERIAL_DEBUG_OPEN
                        printk("doing serial hangup...");
 #endif
-                       if (info->tty)
-                               tty_hangup(info->tty);
+                       if (port->tty)
+                               tty_hangup(port->tty);
                }
        }
-       if (info->flags & ASYNC_CTS_FLOW) {
-               if (info->tty->hw_stopped) {
+       if (port->flags & ASYNC_CTS_FLOW) {
+               if (port->tty->hw_stopped) {
                        if (!(status & SER_CTS)) {
 #if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
                                printk("CTS tx start...");
 #endif
-                               info->tty->hw_stopped = 0;
+                               port->tty->hw_stopped = 0;
                                info->IER |= UART_IER_THRI;
                                custom.intena = IF_SETCLR | IF_TBE;
                                mb();
                                /* set a pending Tx Interrupt, transmitter should restart now */
                                custom.intreq = IF_SETCLR | IF_TBE;
                                mb();
-                               rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+                               tty_wakeup(port->tty);
                                return;
                        }
                } else {
@@ -435,7 +424,7 @@ static void check_modem_status(struct async_struct *info)
 #if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
                                printk("CTS tx stop...");
 #endif
-                               info->tty->hw_stopped = 1;
+                               port->tty->hw_stopped = 1;
                                info->IER &= ~UART_IER_THRI;
                                /* disable Tx interrupt and remove any pending interrupts */
                                custom.intena = IF_TBE;
@@ -450,7 +439,7 @@ static void check_modem_status(struct async_struct *info)
 static irqreturn_t ser_vbl_int( int irq, void *data)
 {
         /* vbl is just a periodic interrupt we tie into to update modem status */
-       struct async_struct * info = IRQ_ports;
+       struct serial_state *info = data;
        /*
         * TBD - is it better to unregister from this interrupt or to
         * ignore it if MSI is clear ?
@@ -462,18 +451,16 @@ static irqreturn_t ser_vbl_int( int irq, void *data)
 
 static irqreturn_t ser_rx_int(int irq, void *dev_id)
 {
-       struct async_struct * info;
+       struct serial_state *info = dev_id;
 
 #ifdef SERIAL_DEBUG_INTR
        printk("ser_rx_int...");
 #endif
 
-       info = IRQ_ports;
-       if (!info || !info->tty)
+       if (!info->tport.tty)
                return IRQ_NONE;
 
        receive_chars(info);
-       info->last_active = jiffies;
 #ifdef SERIAL_DEBUG_INTR
        printk("end.\n");
 #endif
@@ -482,19 +469,17 @@ static irqreturn_t ser_rx_int(int irq, void *dev_id)
 
 static irqreturn_t ser_tx_int(int irq, void *dev_id)
 {
-       struct async_struct * info;
+       struct serial_state *info = dev_id;
 
        if (custom.serdatr & SDR_TBE) {
 #ifdef SERIAL_DEBUG_INTR
          printk("ser_tx_int...");
 #endif
 
-         info = IRQ_ports;
-         if (!info || !info->tty)
+         if (!info->tport.tty)
                return IRQ_NONE;
 
          transmit_chars(info);
-         info->last_active = jiffies;
 #ifdef SERIAL_DEBUG_INTR
          printk("end.\n");
 #endif
@@ -508,29 +493,6 @@ static irqreturn_t ser_tx_int(int irq, void *dev_id)
  * -------------------------------------------------------------------
  */
 
-/*
- * This routine is used to handle the "bottom half" processing for the
- * serial driver, known also the "software interrupt" processing.
- * This processing is done at the kernel interrupt level, after the
- * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON.  This
- * is where time-consuming activities which can not be done in the
- * interrupt driver proper are done; the interrupt driver schedules
- * them using rs_sched_event(), and they get done here.
- */
-
-static void do_softint(unsigned long private_)
-{
-       struct async_struct     *info = (struct async_struct *) private_;
-       struct tty_struct       *tty;
-
-       tty = info->tty;
-       if (!tty)
-               return;
-
-       if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event))
-               tty_wakeup(tty);
-}
-
 /*
  * ---------------------------------------------------------------
  * Low level utility subroutines for the serial driver:  routines to
@@ -540,8 +502,9 @@ static void do_softint(unsigned long private_)
  * ---------------------------------------------------------------
  */
 
-static int startup(struct async_struct * info)
+static int startup(struct tty_struct *tty, struct serial_state *info)
 {
+       struct tty_port *port = &info->tport;
        unsigned long flags;
        int     retval=0;
        unsigned long page;
@@ -552,7 +515,7 @@ static int startup(struct async_struct * info)
 
        local_irq_save(flags);
 
-       if (info->flags & ASYNC_INITIALIZED) {
+       if (port->flags & ASYNC_INITIALIZED) {
                free_page(page);
                goto errout;
        }
@@ -574,9 +537,7 @@ static int startup(struct async_struct * info)
        retval = request_irq(IRQ_AMIGA_VERTB, ser_vbl_int, 0, "serial status", info);
        if (retval) {
          if (serial_isroot()) {
-           if (info->tty)
-             set_bit(TTY_IO_ERROR,
-                     &info->tty->flags);
+             set_bit(TTY_IO_ERROR, &tty->flags);
            retval = 0;
          }
          goto errout;
@@ -590,37 +551,32 @@ static int startup(struct async_struct * info)
        /* remember current state of the DCD and CTS bits */
        current_ctl_bits = ciab.pra & (SER_DCD | SER_CTS | SER_DSR);
 
-       IRQ_ports = info;
-
        info->MCR = 0;
-       if (info->tty->termios->c_cflag & CBAUD)
+       if (C_BAUD(tty))
          info->MCR = SER_DTR | SER_RTS;
        rtsdtr_ctrl(info->MCR);
 
-       if (info->tty)
-               clear_bit(TTY_IO_ERROR, &info->tty->flags);
+       clear_bit(TTY_IO_ERROR, &tty->flags);
        info->xmit.head = info->xmit.tail = 0;
 
        /*
         * Set up the tty->alt_speed kludge
         */
-       if (info->tty) {
-               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;
-       }
+       if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+               tty->alt_speed = 57600;
+       if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+               tty->alt_speed = 115200;
+       if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+               tty->alt_speed = 230400;
+       if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+               tty->alt_speed = 460800;
 
        /*
         * and set the speed of the serial port
         */
-       change_speed(info, NULL);
+       change_speed(tty, info, NULL);
 
-       info->flags |= ASYNC_INITIALIZED;
+       port->flags |= ASYNC_INITIALIZED;
        local_irq_restore(flags);
        return 0;
 
@@ -633,15 +589,15 @@ errout:
  * This routine will shutdown a serial port; interrupts are disabled, and
  * DTR is dropped if the hangup on close termio flag is on.
  */
-static void shutdown(struct async_struct * info)
+static void shutdown(struct tty_struct *tty, struct serial_state *info)
 {
        unsigned long   flags;
        struct serial_state *state;
 
-       if (!(info->flags & ASYNC_INITIALIZED))
+       if (!(info->tport.flags & ASYNC_INITIALIZED))
                return;
 
-       state = info->state;
+       state = info;
 
 #ifdef SERIAL_DEBUG_OPEN
        printk("Shutting down serial port %d ....\n", info->line);
@@ -653,9 +609,7 @@ static void shutdown(struct async_struct * info)
         * clear delta_msr_wait queue to avoid mem leaks: we may free the irq
         * here so the queue might never be waken up
         */
-       wake_up_interruptible(&info->delta_msr_wait);
-
-       IRQ_ports = NULL;
+       wake_up_interruptible(&info->tport.delta_msr_wait);
 
        /*
         * Free the IRQ, if necessary
@@ -675,14 +629,13 @@ static void shutdown(struct async_struct * info)
        custom.adkcon = AC_UARTBRK;
        mb();
 
-       if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
+       if (tty->termios->c_cflag & HUPCL)
                info->MCR &= ~(SER_DTR|SER_RTS);
        rtsdtr_ctrl(info->MCR);
 
-       if (info->tty)
-               set_bit(TTY_IO_ERROR, &info->tty->flags);
+       set_bit(TTY_IO_ERROR, &tty->flags);
 
-       info->flags &= ~ASYNC_INITIALIZED;
+       info->tport.flags &= ~ASYNC_INITIALIZED;
        local_irq_restore(flags);
 }
 
@@ -691,17 +644,16 @@ static void shutdown(struct async_struct * info)
  * This routine is called to set the UART divisor registers to match
  * the specified baud rate for a serial port.
  */
-static void change_speed(struct async_struct *info,
+static void change_speed(struct tty_struct *tty, struct serial_state *info,
                         struct ktermios *old_termios)
 {
+       struct tty_port *port = &info->tport;
        int     quot = 0, baud_base, baud;
        unsigned cflag, cval = 0;
        int     bits;
        unsigned long   flags;
 
-       if (!info->tty || !info->tty->termios)
-               return;
-       cflag = info->tty->termios->c_cflag;
+       cflag = tty->termios->c_cflag;
 
        /* Byte size is always 8 bits plus parity bit if requested */
 
@@ -722,13 +674,12 @@ static void change_speed(struct async_struct *info,
 #endif
 
        /* Determine divisor based on baud rate */
-       baud = tty_get_baud_rate(info->tty);
+       baud = tty_get_baud_rate(tty);
        if (!baud)
                baud = 9600;    /* B0 transition handled in rs_set_termios */
-       baud_base = info->state->baud_base;
-       if (baud == 38400 &&
-           ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))
-               quot = info->state->custom_divisor;
+       baud_base = info->baud_base;
+       if (baud == 38400 && (port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)
+               quot = info->custom_divisor;
        else {
                if (baud == 134)
                        /* Special case since 134 is really 134.5 */
@@ -739,14 +690,14 @@ static void change_speed(struct async_struct *info,
        /* If the quotient is zero refuse the change */
        if (!quot && old_termios) {
                /* FIXME: Will need updating for new tty in the end */
-               info->tty->termios->c_cflag &= ~CBAUD;
-               info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD);
-               baud = tty_get_baud_rate(info->tty);
+               tty->termios->c_cflag &= ~CBAUD;
+               tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD);
+               baud = tty_get_baud_rate(tty);
                if (!baud)
                        baud = 9600;
                if (baud == 38400 &&
-                   ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))
-                       quot = info->state->custom_divisor;
+                   (port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)
+                       quot = info->custom_divisor;
                else {
                        if (baud == 134)
                                /* Special case since 134 is really 134.5 */
@@ -764,17 +715,17 @@ static void change_speed(struct async_struct *info,
 
        /* CTS flow control flag and modem status interrupts */
        info->IER &= ~UART_IER_MSI;
-       if (info->flags & ASYNC_HARDPPS_CD)
+       if (port->flags & ASYNC_HARDPPS_CD)
                info->IER |= UART_IER_MSI;
        if (cflag & CRTSCTS) {
-               info->flags |= ASYNC_CTS_FLOW;
+               port->flags |= ASYNC_CTS_FLOW;
                info->IER |= UART_IER_MSI;
        } else
-               info->flags &= ~ASYNC_CTS_FLOW;
+               port->flags &= ~ASYNC_CTS_FLOW;
        if (cflag & CLOCAL)
-               info->flags &= ~ASYNC_CHECK_CD;
+               port->flags &= ~ASYNC_CHECK_CD;
        else {
-               info->flags |= ASYNC_CHECK_CD;
+               port->flags |= ASYNC_CHECK_CD;
                info->IER |= UART_IER_MSI;
        }
        /* TBD:
@@ -786,24 +737,24 @@ static void change_speed(struct async_struct *info,
         */
 
        info->read_status_mask = UART_LSR_OE | UART_LSR_DR;
-       if (I_INPCK(info->tty))
+       if (I_INPCK(tty))
                info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
-       if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
+       if (I_BRKINT(tty) || I_PARMRK(tty))
                info->read_status_mask |= UART_LSR_BI;
 
        /*
         * Characters to ignore
         */
        info->ignore_status_mask = 0;
-       if (I_IGNPAR(info->tty))
+       if (I_IGNPAR(tty))
                info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
-       if (I_IGNBRK(info->tty)) {
+       if (I_IGNBRK(tty)) {
                info->ignore_status_mask |= UART_LSR_BI;
                /*
                 * If we're ignore parity and break indicators, ignore 
                 * overruns too.  (For real raw support).
                 */
-               if (I_IGNPAR(info->tty))
+               if (I_IGNPAR(tty))
                        info->ignore_status_mask |= UART_LSR_OE;
        }
        /*
@@ -828,13 +779,12 @@ static void change_speed(struct async_struct *info,
        mb();
        }
 
-       info->LCR = cval;                               /* Save LCR */
        local_irq_restore(flags);
 }
 
 static int rs_put_char(struct tty_struct *tty, unsigned char ch)
 {
-       struct async_struct *info;
+       struct serial_state *info;
        unsigned long flags;
 
        info = tty->driver_data;
@@ -861,7 +811,7 @@ static int rs_put_char(struct tty_struct *tty, unsigned char ch)
 
 static void rs_flush_chars(struct tty_struct *tty)
 {
-       struct async_struct *info = tty->driver_data;
+       struct serial_state *info = tty->driver_data;
        unsigned long flags;
 
        if (serial_paranoia_check(info, tty->name, "rs_flush_chars"))
@@ -886,11 +836,9 @@ static void rs_flush_chars(struct tty_struct *tty)
 static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count)
 {
        int     c, ret = 0;
-       struct async_struct *info;
+       struct serial_state *info = tty->driver_data;
        unsigned long flags;
 
-       info = tty->driver_data;
-
        if (serial_paranoia_check(info, tty->name, "rs_write"))
                return 0;
 
@@ -934,7 +882,7 @@ static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count
 
 static int rs_write_room(struct tty_struct *tty)
 {
-       struct async_struct *info = tty->driver_data;
+       struct serial_state *info = tty->driver_data;
 
        if (serial_paranoia_check(info, tty->name, "rs_write_room"))
                return 0;
@@ -943,7 +891,7 @@ static int rs_write_room(struct tty_struct *tty)
 
 static int rs_chars_in_buffer(struct tty_struct *tty)
 {
-       struct async_struct *info = tty->driver_data;
+       struct serial_state *info = tty->driver_data;
 
        if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer"))
                return 0;
@@ -952,7 +900,7 @@ static int rs_chars_in_buffer(struct tty_struct *tty)
 
 static void rs_flush_buffer(struct tty_struct *tty)
 {
-       struct async_struct *info = tty->driver_data;
+       struct serial_state *info = tty->driver_data;
        unsigned long flags;
 
        if (serial_paranoia_check(info, tty->name, "rs_flush_buffer"))
@@ -969,7 +917,7 @@ static void rs_flush_buffer(struct tty_struct *tty)
  */
 static void rs_send_xchar(struct tty_struct *tty, char ch)
 {
-       struct async_struct *info = tty->driver_data;
+       struct serial_state *info = tty->driver_data;
         unsigned long flags;
 
        if (serial_paranoia_check(info, tty->name, "rs_send_char"))
@@ -1004,7 +952,7 @@ static void rs_send_xchar(struct tty_struct *tty, char ch)
  */
 static void rs_throttle(struct tty_struct * tty)
 {
-       struct async_struct *info = tty->driver_data;
+       struct serial_state *info = tty->driver_data;
        unsigned long flags;
 #ifdef SERIAL_DEBUG_THROTTLE
        char    buf[64];
@@ -1029,7 +977,7 @@ static void rs_throttle(struct tty_struct * tty)
 
 static void rs_unthrottle(struct tty_struct * tty)
 {
-       struct async_struct *info = tty->driver_data;
+       struct serial_state *info = tty->driver_data;
        unsigned long flags;
 #ifdef SERIAL_DEBUG_THROTTLE
        char    buf[64];
@@ -1060,25 +1008,22 @@ static void rs_unthrottle(struct tty_struct * tty)
  * ------------------------------------------------------------
  */
 
-static int get_serial_info(struct async_struct * info,
+static int get_serial_info(struct tty_struct *tty, struct serial_state *state,
                           struct serial_struct __user * retinfo)
 {
        struct serial_struct tmp;
-       struct serial_state *state = info->state;
    
        if (!retinfo)
                return -EFAULT;
        memset(&tmp, 0, sizeof(tmp));
        tty_lock();
-       tmp.type = state->type;
-       tmp.line = state->line;
+       tmp.line = tty->index;
        tmp.port = state->port;
-       tmp.irq = state->irq;
-       tmp.flags = state->flags;
+       tmp.flags = state->tport.flags;
        tmp.xmit_fifo_size = state->xmit_fifo_size;
        tmp.baud_base = state->baud_base;
-       tmp.close_delay = state->close_delay;
-       tmp.closing_wait = state->closing_wait;
+       tmp.close_delay = state->tport.close_delay;
+       tmp.closing_wait = state->tport.closing_wait;
        tmp.custom_divisor = state->custom_divisor;
        tty_unlock();
        if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
@@ -1086,38 +1031,34 @@ static int get_serial_info(struct async_struct * info,
        return 0;
 }
 
-static int set_serial_info(struct async_struct * info,
+static int set_serial_info(struct tty_struct *tty, struct serial_state *state,
                           struct serial_struct __user * new_info)
 {
+       struct tty_port *port = &state->tport;
        struct serial_struct new_serial;
-       struct serial_state old_state, *state;
-       unsigned int            change_irq,change_port;
+       bool change_spd;
        int                     retval = 0;
 
        if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
                return -EFAULT;
 
        tty_lock();
-       state = info->state;
-       old_state = *state;
-  
-       change_irq = new_serial.irq != state->irq;
-       change_port = (new_serial.port != state->port);
-       if(change_irq || change_port || (new_serial.xmit_fifo_size != state->xmit_fifo_size)) {
-         tty_unlock();
-         return -EINVAL;
+       change_spd = ((new_serial.flags ^ port->flags) & ASYNC_SPD_MASK) ||
+               new_serial.custom_divisor != state->custom_divisor;
+       if (new_serial.irq || new_serial.port != state->port ||
+                       new_serial.xmit_fifo_size != state->xmit_fifo_size) {
+               tty_unlock();
+               return -EINVAL;
        }
   
        if (!serial_isroot()) {
                if ((new_serial.baud_base != state->baud_base) ||
-                   (new_serial.close_delay != state->close_delay) ||
+                   (new_serial.close_delay != port->close_delay) ||
                    (new_serial.xmit_fifo_size != state->xmit_fifo_size) ||
                    ((new_serial.flags & ~ASYNC_USR_MASK) !=
-                    (state->flags & ~ASYNC_USR_MASK)))
+                    (port->flags & ~ASYNC_USR_MASK)))
                        return -EPERM;
-               state->flags = ((state->flags & ~ASYNC_USR_MASK) |
-                              (new_serial.flags & ASYNC_USR_MASK));
-               info->flags = ((info->flags & ~ASYNC_USR_MASK) |
+               port->flags = ((port->flags & ~ASYNC_USR_MASK) |
                               (new_serial.flags & ASYNC_USR_MASK));
                state->custom_divisor = new_serial.custom_divisor;
                goto check_and_exit;
@@ -1134,32 +1075,28 @@ static int set_serial_info(struct async_struct * info,
         */
 
        state->baud_base = new_serial.baud_base;
-       state->flags = ((state->flags & ~ASYNC_FLAGS) |
+       port->flags = ((port->flags & ~ASYNC_FLAGS) |
                        (new_serial.flags & ASYNC_FLAGS));
-       info->flags = ((state->flags & ~ASYNC_INTERNAL_FLAGS) |
-                      (info->flags & ASYNC_INTERNAL_FLAGS));
        state->custom_divisor = new_serial.custom_divisor;
-       state->close_delay = new_serial.close_delay * HZ/100;
-       state->closing_wait = new_serial.closing_wait * HZ/100;
-       info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+       port->close_delay = new_serial.close_delay * HZ/100;
+       port->closing_wait = new_serial.closing_wait * HZ/100;
+       tty->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
 
 check_and_exit:
-       if (info->flags & ASYNC_INITIALIZED) {
-               if (((old_state.flags & ASYNC_SPD_MASK) !=
-                    (state->flags & ASYNC_SPD_MASK)) ||
-                   (old_state.custom_divisor != state->custom_divisor)) {
-                       if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
-                               info->tty->alt_speed = 57600;
-                       if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
-                               info->tty->alt_speed = 115200;
-                       if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
-                               info->tty->alt_speed = 230400;
-                       if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
-                               info->tty->alt_speed = 460800;
-                       change_speed(info, NULL);
+       if (port->flags & ASYNC_INITIALIZED) {
+               if (change_spd) {
+                       if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+                               tty->alt_speed = 57600;
+                       if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+                               tty->alt_speed = 115200;
+                       if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+                               tty->alt_speed = 230400;
+                       if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+                               tty->alt_speed = 460800;
+                       change_speed(tty, state, NULL);
                }
        } else
-               retval = startup(info);
+               retval = startup(tty, state);
        tty_unlock();
        return retval;
 }
@@ -1175,7 +1112,7 @@ check_and_exit:
  *         transmit holding register is empty.  This functionality
  *         allows an RS485 driver to be written in user space. 
  */
-static int get_lsr_info(struct async_struct * info, unsigned int __user *value)
+static int get_lsr_info(struct serial_state *info, unsigned int __user *value)
 {
        unsigned char status;
        unsigned int result;
@@ -1194,7 +1131,7 @@ static int get_lsr_info(struct async_struct * info, unsigned int __user *value)
 
 static int rs_tiocmget(struct tty_struct *tty)
 {
-       struct async_struct * info = tty->driver_data;
+       struct serial_state *info = tty->driver_data;
        unsigned char control, status;
        unsigned long flags;
 
@@ -1217,7 +1154,7 @@ static int rs_tiocmget(struct tty_struct *tty)
 static int rs_tiocmset(struct tty_struct *tty, unsigned int set,
                                                unsigned int clear)
 {
-       struct async_struct * info = tty->driver_data;
+       struct serial_state *info = tty->driver_data;
        unsigned long flags;
 
        if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
@@ -1244,7 +1181,7 @@ static int rs_tiocmset(struct tty_struct *tty, unsigned int set,
  */
 static int rs_break(struct tty_struct *tty, int break_state)
 {
-       struct async_struct * info = tty->driver_data;
+       struct serial_state *info = tty->driver_data;
        unsigned long flags;
 
        if (serial_paranoia_check(info, tty->name, "rs_break"))
@@ -1269,12 +1206,12 @@ static int rs_break(struct tty_struct *tty, int break_state)
 static int rs_get_icount(struct tty_struct *tty,
                                struct serial_icounter_struct *icount)
 {
-       struct async_struct *info = tty->driver_data;
+       struct serial_state *info = tty->driver_data;
        struct async_icount cnow;
        unsigned long flags;
 
        local_irq_save(flags);
-       cnow = info->state->icount;
+       cnow = info->icount;
        local_irq_restore(flags);
        icount->cts = cnow.cts;
        icount->dsr = cnow.dsr;
@@ -1294,7 +1231,7 @@ static int rs_get_icount(struct tty_struct *tty,
 static int rs_ioctl(struct tty_struct *tty,
                    unsigned int cmd, unsigned long arg)
 {
-       struct async_struct * info = tty->driver_data;
+       struct serial_state *info = tty->driver_data;
        struct async_icount cprev, cnow;        /* kernel counter temps */
        void __user *argp = (void __user *)arg;
        unsigned long flags;
@@ -1311,9 +1248,9 @@ static int rs_ioctl(struct tty_struct *tty,
 
        switch (cmd) {
                case TIOCGSERIAL:
-                       return get_serial_info(info, argp);
+                       return get_serial_info(tty, info, argp);
                case TIOCSSERIAL:
-                       return set_serial_info(info, argp);
+                       return set_serial_info(tty, info, argp);
                case TIOCSERCONFIG:
                        return 0;
 
@@ -1322,7 +1259,7 @@ static int rs_ioctl(struct tty_struct *tty,
 
                case TIOCSERGSTRUCT:
                        if (copy_to_user(argp,
-                                        info, sizeof(struct async_struct)))
+                                        info, sizeof(struct serial_state)))
                                return -EFAULT;
                        return 0;
 
@@ -1335,15 +1272,15 @@ static int rs_ioctl(struct tty_struct *tty,
                case TIOCMIWAIT:
                        local_irq_save(flags);
                        /* note the counters on entry */
-                       cprev = info->state->icount;
+                       cprev = info->icount;
                        local_irq_restore(flags);
                        while (1) {
-                               interruptible_sleep_on(&info->delta_msr_wait);
+                               interruptible_sleep_on(&info->tport.delta_msr_wait);
                                /* see if a signal did it */
                                if (signal_pending(current))
                                        return -ERESTARTSYS;
                                local_irq_save(flags);
-                               cnow = info->state->icount; /* atomic copy */
+                               cnow = info->icount; /* atomic copy */
                                local_irq_restore(flags);
                                if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && 
                                    cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
@@ -1372,11 +1309,11 @@ static int rs_ioctl(struct tty_struct *tty,
 
 static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
 {
-       struct async_struct *info = tty->driver_data;
+       struct serial_state *info = tty->driver_data;
        unsigned long flags;
        unsigned int cflag = tty->termios->c_cflag;
 
-       change_speed(info, old_termios);
+       change_speed(tty, info, old_termios);
 
        /* Handle transition to B0 status */
        if ((old_termios->c_cflag & CBAUD) &&
@@ -1432,15 +1369,13 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
  */
 static void rs_close(struct tty_struct *tty, struct file * filp)
 {
-       struct async_struct * info = tty->driver_data;
-       struct serial_state *state;
+       struct serial_state *state = tty->driver_data;
+       struct tty_port *port = &state->tport;
        unsigned long flags;
 
-       if (!info || serial_paranoia_check(info, tty->name, "rs_close"))
+       if (!state || serial_paranoia_check(state, tty->name, "rs_close"))
                return;
 
-       state = info->state;
-
        local_irq_save(flags);
 
        if (tty_hung_up_p(filp)) {
@@ -1450,46 +1385,46 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
        }
 
 #ifdef SERIAL_DEBUG_OPEN
-       printk("rs_close ttys%d, count = %d\n", info->line, state->count);
+       printk("rs_close ttys%d, count = %d\n", state->line, port->count);
 #endif
-       if ((tty->count == 1) && (state->count != 1)) {
+       if ((tty->count == 1) && (port->count != 1)) {
                /*
                 * Uh, oh.  tty->count is 1, which means that the tty
-                * structure will be freed.  state->count should always
+                * structure will be freed.  port->count should always
                 * be one in these conditions.  If it's greater than
                 * one, we've got real problems, since it means the
                 * serial port won't be shutdown.
                 */
                printk("rs_close: bad serial port count; tty->count is 1, "
-                      "state->count is %d\n", state->count);
-               state->count = 1;
+                      "port->count is %d\n", state->tport.count);
+               port->count = 1;
        }
-       if (--state->count < 0) {
+       if (--port->count < 0) {
                printk("rs_close: bad serial port count for ttys%d: %d\n",
-                      info->line, state->count);
-               state->count = 0;
+                      tty->index, port->count);
+               port->count = 0;
        }
-       if (state->count) {
+       if (port->count) {
                DBG_CNT("before DEC-2");
                local_irq_restore(flags);
                return;
        }
-       info->flags |= ASYNC_CLOSING;
+       port->flags |= ASYNC_CLOSING;
        /*
         * Now we wait for the transmit buffer to clear; and we notify 
         * the line discipline to only process XON/XOFF characters.
         */
        tty->closing = 1;
-       if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-               tty_wait_until_sent(tty, info->closing_wait);
+       if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+               tty_wait_until_sent(tty, port->closing_wait);
        /*
         * At this point we stop accepting input.  To do this, we
         * disable the receive line status interrupts, and tell the
         * interrupt driver to stop checking the data ready bit in the
         * line status register.
         */
-       info->read_status_mask &= ~UART_LSR_DR;
-       if (info->flags & ASYNC_INITIALIZED) {
+       state->read_status_mask &= ~UART_LSR_DR;
+       if (port->flags & ASYNC_INITIALIZED) {
                /* disable receive interrupts */
                custom.intena = IF_RBF;
                mb();
@@ -1502,23 +1437,22 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
                 * has completely drained; this is especially
                 * important if there is a transmit FIFO!
                 */
-               rs_wait_until_sent(tty, info->timeout);
+               rs_wait_until_sent(tty, state->timeout);
        }
-       shutdown(info);
+       shutdown(tty, state);
        rs_flush_buffer(tty);
                
        tty_ldisc_flush(tty);
        tty->closing = 0;
-       info->event = 0;
-       info->tty = NULL;
-       if (info->blocked_open) {
-               if (info->close_delay) {
-                       msleep_interruptible(jiffies_to_msecs(info->close_delay));
+       port->tty = NULL;
+       if (port->blocked_open) {
+               if (port->close_delay) {
+                       msleep_interruptible(jiffies_to_msecs(port->close_delay));
                }
-               wake_up_interruptible(&info->open_wait);
+               wake_up_interruptible(&port->open_wait);
        }
-       info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
-       wake_up_interruptible(&info->close_wait);
+       port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
+       wake_up_interruptible(&port->close_wait);
        local_irq_restore(flags);
 }
 
@@ -1527,7 +1461,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
  */
 static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
 {
-       struct async_struct * info = tty->driver_data;
+       struct serial_state *info = tty->driver_data;
        unsigned long orig_jiffies, char_time;
        int lsr;
 
@@ -1590,21 +1524,17 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
  */
 static void rs_hangup(struct tty_struct *tty)
 {
-       struct async_struct * info = tty->driver_data;
-       struct serial_state *state = info->state;
+       struct serial_state *info = tty->driver_data;
 
        if (serial_paranoia_check(info, tty->name, "rs_hangup"))
                return;
 
-       state = info->state;
-
        rs_flush_buffer(tty);
-       shutdown(info);
-       info->event = 0;
-       state->count = 0;
-       info->flags &= ~ASYNC_NORMAL_ACTIVE;
-       info->tty = NULL;
-       wake_up_interruptible(&info->open_wait);
+       shutdown(tty, info);
+       info->tport.count = 0;
+       info->tport.flags &= ~ASYNC_NORMAL_ACTIVE;
+       info->tport.tty = NULL;
+       wake_up_interruptible(&info->tport.open_wait);
 }
 
 /*
@@ -1613,14 +1543,14 @@ static void rs_hangup(struct tty_struct *tty)
  * ------------------------------------------------------------
  */
 static int block_til_ready(struct tty_struct *tty, struct file * filp,
-                          struct async_struct *info)
+                          struct serial_state *info)
 {
 #ifdef DECLARE_WAITQUEUE
        DECLARE_WAITQUEUE(wait, current);
 #else
        struct wait_queue wait = { current, NULL };
 #endif
-       struct serial_state *state = info->state;
+       struct tty_port *port = &info->tport;
        int             retval;
        int             do_clocal = 0, extra_count = 0;
        unsigned long   flags;
@@ -1630,11 +1560,11 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
         * until it's done, and then try again.
         */
        if (tty_hung_up_p(filp) ||
-           (info->flags & ASYNC_CLOSING)) {
-               if (info->flags & ASYNC_CLOSING)
-                       interruptible_sleep_on(&info->close_wait);
+           (port->flags & ASYNC_CLOSING)) {
+               if (port->flags & ASYNC_CLOSING)
+                       interruptible_sleep_on(&port->close_wait);
 #ifdef SERIAL_DO_RESTART
-               return ((info->flags & ASYNC_HUP_NOTIFY) ?
+               return ((port->flags & ASYNC_HUP_NOTIFY) ?
                        -EAGAIN : -ERESTARTSYS);
 #else
                return -EAGAIN;
@@ -1647,7 +1577,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
         */
        if ((filp->f_flags & O_NONBLOCK) ||
            (tty->flags & (1 << TTY_IO_ERROR))) {
-               info->flags |= ASYNC_NORMAL_ACTIVE;
+               port->flags |= ASYNC_NORMAL_ACTIVE;
                return 0;
        }
 
@@ -1657,23 +1587,23 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
        /*
         * Block waiting for the carrier detect and the line to become
         * free (i.e., not in use by the callout).  While we are in
-        * this loop, state->count is dropped by one, so that
+        * this loop, port->count is dropped by one, so that
         * rs_close() knows when to free things.  We restore it upon
         * exit, either normal or abnormal.
         */
        retval = 0;
-       add_wait_queue(&info->open_wait, &wait);
+       add_wait_queue(&port->open_wait, &wait);
 #ifdef SERIAL_DEBUG_OPEN
        printk("block_til_ready before block: ttys%d, count = %d\n",
-              state->line, state->count);
+              info->line, port->count);
 #endif
        local_irq_save(flags);
        if (!tty_hung_up_p(filp)) {
                extra_count = 1;
-               state->count--;
+               port->count--;
        }
        local_irq_restore(flags);
-       info->blocked_open++;
+       port->blocked_open++;
        while (1) {
                local_irq_save(flags);
                if (tty->termios->c_cflag & CBAUD)
@@ -1681,9 +1611,9 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
                local_irq_restore(flags);
                set_current_state(TASK_INTERRUPTIBLE);
                if (tty_hung_up_p(filp) ||
-                   !(info->flags & ASYNC_INITIALIZED)) {
+                   !(port->flags & ASYNC_INITIALIZED)) {
 #ifdef SERIAL_DO_RESTART
-                       if (info->flags & ASYNC_HUP_NOTIFY)
+                       if (port->flags & ASYNC_HUP_NOTIFY)
                                retval = -EAGAIN;
                        else
                                retval = -ERESTARTSYS;
@@ -1692,7 +1622,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
 #endif
                        break;
                }
-               if (!(info->flags & ASYNC_CLOSING) &&
+               if (!(port->flags & ASYNC_CLOSING) &&
                    (do_clocal || (!(ciab.pra & SER_DCD)) ))
                        break;
                if (signal_pending(current)) {
@@ -1701,61 +1631,24 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
                }
 #ifdef SERIAL_DEBUG_OPEN
                printk("block_til_ready blocking: ttys%d, count = %d\n",
-                      info->line, state->count);
+                      info->line, port->count);
 #endif
                tty_unlock();
                schedule();
                tty_lock();
        }
        __set_current_state(TASK_RUNNING);
-       remove_wait_queue(&info->open_wait, &wait);
+       remove_wait_queue(&port->open_wait, &wait);
        if (extra_count)
-               state->count++;
-       info->blocked_open--;
+               port->count++;
+       port->blocked_open--;
 #ifdef SERIAL_DEBUG_OPEN
        printk("block_til_ready after blocking: ttys%d, count = %d\n",
-              info->line, state->count);
+              info->line, port->count);
 #endif
        if (retval)
                return retval;
-       info->flags |= ASYNC_NORMAL_ACTIVE;
-       return 0;
-}
-
-static int get_async_struct(int line, struct async_struct **ret_info)
-{
-       struct async_struct *info;
-       struct serial_state *sstate;
-
-       sstate = rs_table + line;
-       sstate->count++;
-       if (sstate->info) {
-               *ret_info = sstate->info;
-               return 0;
-       }
-       info = kzalloc(sizeof(struct async_struct), GFP_KERNEL);
-       if (!info) {
-               sstate->count--;
-               return -ENOMEM;
-       }
-#ifdef DECLARE_WAITQUEUE
-       init_waitqueue_head(&info->open_wait);
-       init_waitqueue_head(&info->close_wait);
-       init_waitqueue_head(&info->delta_msr_wait);
-#endif
-       info->magic = SERIAL_MAGIC;
-       info->port = sstate->port;
-       info->flags = sstate->flags;
-       info->xmit_fifo_size = sstate->xmit_fifo_size;
-       info->line = line;
-       tasklet_init(&info->tlet, do_softint, (unsigned long)info);
-       info->state = sstate;
-       if (sstate->info) {
-               kfree(info);
-               *ret_info = sstate->info;
-               return 0;
-       }
-       *ret_info = sstate->info = info;
+       port->flags |= ASYNC_NORMAL_ACTIVE;
        return 0;
 }
 
@@ -1767,36 +1660,31 @@ static int get_async_struct(int line, struct async_struct **ret_info)
  */
 static int rs_open(struct tty_struct *tty, struct file * filp)
 {
-       struct async_struct     *info;
-       int                     retval, line;
+       struct serial_state *info = rs_table + tty->index;
+       struct tty_port *port = &info->tport;
+       int retval;
 
-       line = tty->index;
-       if ((line < 0) || (line >= NR_PORTS)) {
-               return -ENODEV;
-       }
-       retval = get_async_struct(line, &info);
-       if (retval) {
-               return retval;
-       }
+       port->count++;
+       port->tty = tty;
        tty->driver_data = info;
-       info->tty = tty;
+       tty->port = port;
        if (serial_paranoia_check(info, tty->name, "rs_open"))
                return -ENODEV;
 
 #ifdef SERIAL_DEBUG_OPEN
-       printk("rs_open %s, count = %d\n", tty->name, info->state->count);
+       printk("rs_open %s, count = %d\n", tty->name, info->count);
 #endif
-       info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+       tty->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
 
        /*
         * If the port is the middle of closing, bail out now
         */
        if (tty_hung_up_p(filp) ||
-           (info->flags & ASYNC_CLOSING)) {
-               if (info->flags & ASYNC_CLOSING)
-                       interruptible_sleep_on(&info->close_wait);
+           (port->flags & ASYNC_CLOSING)) {
+               if (port->flags & ASYNC_CLOSING)
+                       interruptible_sleep_on(&port->close_wait);
 #ifdef SERIAL_DO_RESTART
-               return ((info->flags & ASYNC_HUP_NOTIFY) ?
+               return ((port->flags & ASYNC_HUP_NOTIFY) ?
                        -EAGAIN : -ERESTARTSYS);
 #else
                return -EAGAIN;
@@ -1806,7 +1694,7 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
        /*
         * Start up serial port
         */
-       retval = startup(info);
+       retval = startup(tty, info);
        if (retval) {
                return retval;
        }
@@ -1830,28 +1718,17 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
  * /proc fs routines....
  */
 
-static inline void line_info(struct seq_file *m, struct serial_state *state)
+static inline void line_info(struct seq_file *m, int line,
+               struct serial_state *state)
 {
-       struct async_struct *info = state->info, scr_info;
        char    stat_buf[30], control, status;
        unsigned long flags;
 
-       seq_printf(m, "%d: uart:amiga_builtin",state->line);
-
-       /*
-        * Figure out the current RS-232 lines
-        */
-       if (!info) {
-               info = &scr_info;       /* This is just for serial_{in,out} */
+       seq_printf(m, "%d: uart:amiga_builtin", line);
 
-               info->magic = SERIAL_MAGIC;
-               info->flags = state->flags;
-               info->quot = 0;
-               info->tty = NULL;
-       }
        local_irq_save(flags);
        status = ciab.pra;
-       control = info ? info->MCR : status;
+       control = (state->tport.flags & ASYNC_INITIALIZED) ? state->MCR : status;
        local_irq_restore(flags);
 
        stat_buf[0] = 0;
@@ -1867,9 +1744,8 @@ static inline void line_info(struct seq_file *m, struct serial_state *state)
        if(!(status & SER_DCD))
                strcat(stat_buf, "|CD");
 
-       if (info->quot) {
-               seq_printf(m, " baud:%d", state->baud_base / info->quot);
-       }
+       if (state->quot)
+               seq_printf(m, " baud:%d", state->baud_base / state->quot);
 
        seq_printf(m, " tx:%d rx:%d", state->icount.tx, state->icount.rx);
 
@@ -1894,7 +1770,7 @@ static inline void line_info(struct seq_file *m, struct serial_state *state)
 static int rs_proc_show(struct seq_file *m, void *v)
 {
        seq_printf(m, "serinfo:1.0 driver:%s\n", serial_version);
-       line_info(m, &rs_table[0]);
+       line_info(m, 0, &rs_table[0]);
        return 0;
 }
 
@@ -1964,17 +1840,14 @@ static int __init amiga_serial_probe(struct platform_device *pdev)
        struct serial_state * state;
        int error;
 
-       serial_driver = alloc_tty_driver(1);
+       serial_driver = alloc_tty_driver(NR_PORTS);
        if (!serial_driver)
                return -ENOMEM;
 
-       IRQ_ports = NULL;
-
        show_serial_version();
 
        /* Initialize the tty_driver structure */
 
-       serial_driver->owner = THIS_MODULE;
        serial_driver->driver_name = "amiserial";
        serial_driver->name = "ttyS";
        serial_driver->major = TTY_MAJOR;
@@ -1992,20 +1865,16 @@ static int __init amiga_serial_probe(struct platform_device *pdev)
                goto fail_put_tty_driver;
 
        state = rs_table;
-       state->magic = SSTATE_MAGIC;
        state->port = (int)&custom.serdatr; /* Just to give it a value */
-       state->line = 0;
        state->custom_divisor = 0;
-       state->close_delay = 5*HZ/10;
-       state->closing_wait = 30*HZ;
        state->icount.cts = state->icount.dsr = 
          state->icount.rng = state->icount.dcd = 0;
        state->icount.rx = state->icount.tx = 0;
        state->icount.frame = state->icount.parity = 0;
        state->icount.overrun = state->icount.brk = 0;
+       tty_port_init(&state->tport);
 
-       printk(KERN_INFO "ttyS%d is the amiga builtin serial port\n",
-                      state->line);
+       printk(KERN_INFO "ttyS0 is the amiga builtin serial port\n");
 
        /* Hardware set up */
 
@@ -2058,20 +1927,15 @@ static int __exit amiga_serial_remove(struct platform_device *pdev)
 {
        int error;
        struct serial_state *state = platform_get_drvdata(pdev);
-       struct async_struct *info = state->info;
 
        /* printk("Unloading %s: version %s\n", serial_name, serial_version); */
-       tasklet_kill(&info->tlet);
        if ((error = tty_unregister_driver(serial_driver)))
                printk("SERIAL: failed to unregister serial driver (%d)\n",
                       error);
        put_tty_driver(serial_driver);
 
-       rs_table[0].info = NULL;
-       kfree(info);
-
-       free_irq(IRQ_AMIGA_TBE, rs_table);
-       free_irq(IRQ_AMIGA_RBF, rs_table);
+       free_irq(IRQ_AMIGA_TBE, state);
+       free_irq(IRQ_AMIGA_RBF, state);
 
        platform_set_drvdata(pdev, NULL);