Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / char / esp.c
index d67098c..09dc4b0 100644 (file)
@@ -57,6 +57,7 @@
 #include <linux/ioport.h>
 #include <linux/mm.h>
 #include <linux/init.h>
+#include <linux/delay.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -70,6 +71,7 @@
 
 #define NR_PORTS 64    /* maximum number of ports */
 #define NR_PRIMARY 8   /* maximum number of primary ports */
+#define REGION_SIZE 8   /* size of io region to request */
 
 /* The following variables can be set by giving module options */
 static int irq[NR_PRIMARY];    /* IRQ for each base port */
@@ -84,15 +86,15 @@ static unsigned int pio_threshold = ESP_PIO_THRESHOLD;
 
 MODULE_LICENSE("GPL");
 
-MODULE_PARM(irq, "1-8i");
-MODULE_PARM(divisor, "1-8i");
-MODULE_PARM(dma, "i");
-MODULE_PARM(rx_trigger, "i");
-MODULE_PARM(tx_trigger, "i");
-MODULE_PARM(flow_off, "i");
-MODULE_PARM(flow_on, "i");
-MODULE_PARM(rx_timeout, "i");
-MODULE_PARM(pio_threshold, "i");
+module_param_array(irq, int, NULL, 0);
+module_param_array(divisor, uint, NULL, 0);
+module_param(dma, uint, 0);
+module_param(rx_trigger, uint, 0);
+module_param(tx_trigger, uint, 0);
+module_param(flow_off, uint, 0);
+module_param(flow_on, uint, 0);
+module_param(rx_timeout, uint, 0);
+module_param(pio_threshold, uint, 0);
 
 /* END */
 
@@ -127,8 +129,6 @@ static struct tty_driver *esp_driver;
 #undef SERIAL_DEBUG_OPEN
 #undef SERIAL_DEBUG_FLOW
 
-#define _INLINE_ inline
-  
 #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)
@@ -150,18 +150,6 @@ static void rs_wait_until_sent(struct tty_struct *, int);
 /* Standard COM flags (except for COM4, because of the 8514 problem) */
 #define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
 
-/*
- * tmp_buf is used as a temporary buffer by serial_write.  We need to
- * lock it in case the memcpy_fromfs blocks while swapping in a page,
- * and some other program tries to do a serial write at the same time.
- * Since the lock will only come under contention when the system is
- * swapping and available memory is low, it makes sense to share one
- * buffer across all the serial ports, since it significantly saves
- * memory if large numbers of serial ports are open.
- */
-static unsigned char *tmp_buf;
-static DECLARE_MUTEX(tmp_buf_sem);
-
 static inline int serial_paranoia_check(struct esp_struct *info,
                                        char *name, const char *routine)
 {
@@ -209,15 +197,14 @@ static void rs_stop(struct tty_struct *tty)
 
        if (serial_paranoia_check(info, tty->name, "rs_stop"))
                return;
-       
-       save_flags(flags); cli();
+
+       spin_lock_irqsave(&info->lock, flags);
        if (info->IER & UART_IER_THRI) {
                info->IER &= ~UART_IER_THRI;
                serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
                serial_out(info, UART_ESI_CMD2, info->IER);
        }
-
-       restore_flags(flags);
+       spin_unlock_irqrestore(&info->lock, flags);
 }
 
 static void rs_start(struct tty_struct *tty)
@@ -228,13 +215,13 @@ static void rs_start(struct tty_struct *tty)
        if (serial_paranoia_check(info, tty->name, "rs_start"))
                return;
        
-       save_flags(flags); cli();
+       spin_lock_irqsave(&info->lock, flags);
        if (info->xmit_cnt && info->xmit_buf && !(info->IER & UART_IER_THRI)) {
                info->IER |= UART_IER_THRI;
                serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
                serial_out(info, UART_ESI_CMD2, info->IER);
        }
-       restore_flags(flags);
+       spin_unlock_irqrestore(&info->lock, flags);
 }
 
 /*
@@ -262,34 +249,41 @@ 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 _INLINE_ void rs_sched_event(struct esp_struct *info,
+static inline void rs_sched_event(struct esp_struct *info,
                                  int event)
 {
        info->event |= 1 << event;
        schedule_work(&info->tqueue);
 }
 
-static _INLINE_ struct esp_pio_buffer *get_pio_buffer(void)
+static DEFINE_SPINLOCK(pio_lock);
+
+static inline struct esp_pio_buffer *get_pio_buffer(void)
 {
        struct esp_pio_buffer *buf;
+       unsigned long flags;
 
+       spin_lock_irqsave(&pio_lock, flags);
        if (free_pio_buf) {
                buf = free_pio_buf;
                free_pio_buf = buf->next;
        } else {
                buf = kmalloc(sizeof(struct esp_pio_buffer), GFP_ATOMIC);
        }
-
+       spin_unlock_irqrestore(&pio_lock, flags);
        return buf;
 }
 
-static _INLINE_ void release_pio_buffer(struct esp_pio_buffer *buf)
+static inline void release_pio_buffer(struct esp_pio_buffer *buf)
 {
+       unsigned long flags;
+       spin_lock_irqsave(&pio_lock, flags);
        buf->next = free_pio_buf;
        free_pio_buf = buf;
+       spin_unlock_irqrestore(&pio_lock, flags);
 }
 
-static _INLINE_ void receive_chars_pio(struct esp_struct *info, int num_bytes)
+static inline void receive_chars_pio(struct esp_struct *info, int num_bytes)
 {
        struct tty_struct *tty = info->tty;
        int i;
@@ -309,8 +303,6 @@ static _INLINE_ void receive_chars_pio(struct esp_struct *info, int num_bytes)
                return;
        }
 
-       sti();
-       
        status_mask = (info->read_status_mask >> 2) & 0x07;
                
        for (i = 0; i < num_bytes - 1; i += 2) {
@@ -327,8 +319,6 @@ static _INLINE_ void receive_chars_pio(struct esp_struct *info, int num_bytes)
                        (serial_in(info, UART_ESI_RWS) >> 3) & status_mask;
        }
 
-       cli();
-
        /* make sure everything is still ok since interrupts were enabled */
        tty = info->tty;
 
@@ -343,33 +333,29 @@ static _INLINE_ void receive_chars_pio(struct esp_struct *info, int num_bytes)
 
        for (i = 0; i < num_bytes; i++) {
                if (!(err_buf->data[i] & status_mask)) {
-                       *(tty->flip.char_buf_ptr++) = pio_buf->data[i];
+                       int flag = 0;
 
                        if (err_buf->data[i] & 0x04) {
-                               *(tty->flip.flag_buf_ptr++) = TTY_BREAK;
-
+                               flag = TTY_BREAK;
                                if (info->flags & ASYNC_SAK)
                                        do_SAK(tty);
                        }
                        else if (err_buf->data[i] & 0x02)
-                               *(tty->flip.flag_buf_ptr++) = TTY_FRAME;
+                               flag = TTY_FRAME;
                        else if (err_buf->data[i] & 0x01)
-                               *(tty->flip.flag_buf_ptr++) = TTY_PARITY;
-                       else
-                               *(tty->flip.flag_buf_ptr++) = 0;
-               
-                       tty->flip.count++;
+                               flag = TTY_PARITY;
+                       tty_insert_flip_char(tty, pio_buf->data[i], flag);
                }
        }
 
-       schedule_delayed_work(&tty->flip.work, 1);
+       tty_schedule_flip(tty);
 
        info->stat_flags &= ~ESP_STAT_RX_TIMEOUT;
        release_pio_buffer(pio_buf);
        release_pio_buffer(err_buf);
 }
 
-static _INLINE_ void receive_chars_dma(struct esp_struct *info, int num_bytes)
+static inline void receive_chars_dma(struct esp_struct *info, int num_bytes)
 {
        unsigned long flags;
        info->stat_flags &= ~ESP_STAT_RX_TIMEOUT;
@@ -388,14 +374,13 @@ static _INLINE_ void receive_chars_dma(struct esp_struct *info, int num_bytes)
         serial_out(info, UART_ESI_CMD1, ESI_START_DMA_RX);
 }
 
-static _INLINE_ void receive_chars_dma_done(struct esp_struct *info,
+static inline void receive_chars_dma_done(struct esp_struct *info,
                                            int status)
 {
        struct tty_struct *tty = info->tty;
        int num_bytes;
        unsigned long flags;
        
-       
        flags=claim_dma_lock();
        disable_dma(dma);
        clear_dma_ff(dma);
@@ -406,38 +391,31 @@ static _INLINE_ void receive_chars_dma_done(struct esp_struct *info,
        
        info->icount.rx += num_bytes;
 
-       memcpy(tty->flip.char_buf_ptr, dma_buffer, num_bytes);
-       tty->flip.char_buf_ptr += num_bytes;
-       tty->flip.count += num_bytes;
-       memset(tty->flip.flag_buf_ptr, 0, num_bytes);
-       tty->flip.flag_buf_ptr += num_bytes;
-
        if (num_bytes > 0) {
-               tty->flip.flag_buf_ptr--;
+               tty_insert_flip_string(tty, dma_buffer, num_bytes - 1);
 
                status &= (0x1c & info->read_status_mask);
+               
+               /* Is the status significant or do we throw the last byte ? */
+               if (!(status & info->ignore_status_mask)) {
+                       int statflag = 0;
 
-               if (status & info->ignore_status_mask) {
-                       tty->flip.count--;
-                       tty->flip.char_buf_ptr--;
-                       tty->flip.flag_buf_ptr--;
-               } else if (status & 0x10) {
-                       *tty->flip.flag_buf_ptr = TTY_BREAK;
-                       (info->icount.brk)++;
-                       if (info->flags & ASYNC_SAK)
-                               do_SAK(tty);
-               } else if (status & 0x08) {
-                       *tty->flip.flag_buf_ptr = TTY_FRAME;
-                       (info->icount.frame)++;
-               }
-               else if (status & 0x04) {
-                       *tty->flip.flag_buf_ptr = TTY_PARITY;
-                       (info->icount.parity)++;
+                       if (status & 0x10) {
+                               statflag = TTY_BREAK;
+                               (info->icount.brk)++;
+                               if (info->flags & ASYNC_SAK)
+                                       do_SAK(tty);
+                       } else if (status & 0x08) {
+                               statflag = TTY_FRAME;
+                               (info->icount.frame)++;
+                       }
+                       else if (status & 0x04) {
+                               statflag = TTY_PARITY;
+                               (info->icount.parity)++;
+                       }
+                       tty_insert_flip_char(tty, dma_buffer[num_bytes - 1], statflag);
                }
-
-               tty->flip.flag_buf_ptr++;
-               
-               schedule_delayed_work(&tty->flip.work, 1);
+               tty_schedule_flip(tty);
        }
 
        if (dma_bytes != num_bytes) {
@@ -448,7 +426,9 @@ static _INLINE_ void receive_chars_dma_done(struct esp_struct *info,
                dma_bytes = 0;
 }
 
-static _INLINE_ void transmit_chars_pio(struct esp_struct *info,
+/* Caller must hold info->lock */
+
+static inline void transmit_chars_pio(struct esp_struct *info,
                                        int space_avail)
 {
        int i;
@@ -476,8 +456,6 @@ static _INLINE_ void transmit_chars_pio(struct esp_struct *info,
                info->xmit_tail = (info->xmit_tail + space_avail) &
                        (ESP_XMIT_SIZE - 1);
 
-               sti();
-
                for (i = 0; i < space_avail - 1; i += 2) {
                        outw(*((unsigned short *)(pio_buf->data + i)),
                             info->port + UART_ESI_TX);
@@ -487,8 +465,6 @@ static _INLINE_ void transmit_chars_pio(struct esp_struct *info,
                        serial_out(info, UART_ESI_TX,
                                   pio_buf->data[space_avail - 1]);
 
-               cli();
-
                if (info->xmit_cnt) {
                        serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND);
                        serial_out(info, UART_ESI_CMD1, ESI_GET_TX_AVAIL);
@@ -518,7 +494,8 @@ static _INLINE_ void transmit_chars_pio(struct esp_struct *info,
        release_pio_buffer(pio_buf);
 }
 
-static _INLINE_ void transmit_chars_dma(struct esp_struct *info, int num_bytes)
+/* Caller must hold info->lock */
+static inline void transmit_chars_dma(struct esp_struct *info, int num_bytes)
 {
        unsigned long flags;
        
@@ -565,7 +542,7 @@ static _INLINE_ void transmit_chars_dma(struct esp_struct *info, int num_bytes)
         serial_out(info, UART_ESI_CMD1, ESI_START_DMA_TX);
 }
 
-static _INLINE_ void transmit_chars_dma_done(struct esp_struct *info)
+static inline void transmit_chars_dma_done(struct esp_struct *info)
 {
        int num_bytes;
        unsigned long flags;
@@ -599,7 +576,7 @@ static _INLINE_ void transmit_chars_dma_done(struct esp_struct *info)
        }
 }
 
-static _INLINE_ void check_modem_status(struct esp_struct *info)
+static inline void check_modem_status(struct esp_struct *info)
 {
        int     status;
        
@@ -652,10 +629,10 @@ static irqreturn_t rs_interrupt_single(int irq, void *dev_id,
        err_status = 0;
        scratch = serial_in(info, UART_ESI_SID);
 
-       cli();
+       spin_lock(&info->lock);
        
        if (!info->tty) {
-               sti();
+               spin_unlock(&info->lock);
                return IRQ_NONE;
        }
 
@@ -692,8 +669,7 @@ static irqreturn_t rs_interrupt_single(int irq, void *dev_id,
                num_bytes = serial_in(info, UART_ESI_STAT1) << 8;
                num_bytes |= serial_in(info, UART_ESI_STAT2);
 
-               if (num_bytes > (TTY_FLIPBUF_SIZE - info->tty->flip.count))
-                 num_bytes = TTY_FLIPBUF_SIZE - info->tty->flip.count;
+               num_bytes = tty_buffer_request_room(info->tty, num_bytes);
 
                if (num_bytes) {
                        if (dma_bytes ||
@@ -738,7 +714,7 @@ static irqreturn_t rs_interrupt_single(int irq, void *dev_id,
 #ifdef SERIAL_DEBUG_INTR
        printk("end.\n");
 #endif
-       sti();
+       spin_unlock(&info->lock);
        return IRQ_HANDLED;
 }
 
@@ -787,10 +763,12 @@ static void do_serial_hangup(void *private_)
  * figure out the appropriate timeout for an interrupt chain, routines
  * to initialize and startup a serial port, and routines to shutdown a
  * serial port.  Useful stuff like that.
+ *
+ * Caller should hold lock
  * ---------------------------------------------------------------
  */
 
-static _INLINE_ void esp_basic_init(struct esp_struct * info)
+static inline void esp_basic_init(struct esp_struct * info)
 {
        /* put ESPC in enhanced mode */
        serial_out(info, UART_ESI_CMD1, ESI_SET_MODE);
@@ -857,13 +835,13 @@ static int startup(struct esp_struct * info)
        int     retval=0;
         unsigned int num_chars;
 
-       save_flags(flags); cli();
+        spin_lock_irqsave(&info->lock, flags);
 
        if (info->flags & ASYNC_INITIALIZED)
                goto out;
 
        if (!info->xmit_buf) {
-               info->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
+               info->xmit_buf = (unsigned char *)get_zeroed_page(GFP_ATOMIC);
                retval = -ENOMEM;
                if (!info->xmit_buf)
                        goto out;
@@ -899,6 +877,8 @@ static int startup(struct esp_struct * info)
        if (info->stat_flags & ESP_STAT_NEVER_DMA)
                info->stat_flags |= ESP_STAT_USE_PIO;
 
+       spin_unlock_irqrestore(&info->lock, flags);
+
        /*
         * Allocate the IRQ
         */
@@ -913,7 +893,7 @@ static int startup(struct esp_struct * info)
                                        &info->tty->flags);
                        retval = 0;
                }
-               goto out;
+               goto out_unlocked;
        }
 
        if (!(info->stat_flags & ESP_STAT_USE_PIO) && !dma_buffer) {
@@ -933,6 +913,8 @@ static int startup(struct esp_struct * info)
        }
 
        info->MCR = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2;
+
+       spin_lock_irqsave(&info->lock, flags);
        serial_out(info, UART_ESI_CMD1, ESI_WRITE_UART);
        serial_out(info, UART_ESI_CMD2, UART_MCR);
        serial_out(info, UART_ESI_CMD2, info->MCR);
@@ -949,6 +931,7 @@ static int startup(struct esp_struct * info)
        if (info->tty)
                clear_bit(TTY_IO_ERROR, &info->tty->flags);
        info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+       spin_unlock_irqrestore(&info->lock, flags);
 
        /*
         * Set up the tty->alt_speed kludge
@@ -968,10 +951,12 @@ static int startup(struct esp_struct * info)
         * set the speed of the serial port
         */
        change_speed(info);
-
        info->flags |= ASYNC_INITIALIZED;
-       retval = 0;
-out:   restore_flags(flags);
+       return 0;
+
+out:
+       spin_unlock_irqrestore(&info->lock, flags);
+out_unlocked:
        return retval;
 }
 
@@ -991,8 +976,7 @@ static void shutdown(struct esp_struct * info)
               info->irq);
 #endif
        
-       save_flags(flags); cli(); /* Disable interrupts */
-
+       spin_lock_irqsave(&info->lock, flags);
        /*
         * clear delta_msr_wait queue to avoid mem leaks: we may free the irq
         * here so the queue might never be waken up
@@ -1001,7 +985,7 @@ static void shutdown(struct esp_struct * info)
        wake_up_interruptible(&info->break_wait);
 
        /* stop a DMA transfer on the port being closed */
-          
+       /* DMA lock is higher priority always */
        if (info->stat_flags & (ESP_STAT_DMA_RX | ESP_STAT_DMA_TX)) {
                f=claim_dma_lock();
                disable_dma(dma);
@@ -1056,7 +1040,7 @@ static void shutdown(struct esp_struct * info)
                set_bit(TTY_IO_ERROR, &info->tty->flags);
        
        info->flags &= ~ASYNC_INITIALIZED;
-       restore_flags(flags);
+       spin_unlock_irqrestore(&info->lock, flags);
 }
 
 /*
@@ -1170,7 +1154,7 @@ static void change_speed(struct esp_struct *info)
        if (I_IXOFF(info->tty))
                flow1 |= 0x81;
 
-       save_flags(flags); cli();
+       spin_lock_irqsave(&info->lock, flags);
        /* set baud */
        serial_out(info, UART_ESI_CMD1, ESI_SET_BAUD);
        serial_out(info, UART_ESI_CMD2, quot >> 8);
@@ -1217,7 +1201,7 @@ static void change_speed(struct esp_struct *info)
        serial_out(info, UART_ESI_CMD2, info->config.flow_on >> 8);
        serial_out(info, UART_ESI_CMD2, info->config.flow_on);
 
-       restore_flags(flags);
+       spin_unlock_irqrestore(&info->lock, flags);
 }
 
 static void rs_put_char(struct tty_struct *tty, unsigned char ch)
@@ -1231,16 +1215,13 @@ static void rs_put_char(struct tty_struct *tty, unsigned char ch)
        if (!tty || !info->xmit_buf)
                return;
 
-       save_flags(flags); cli();
-       if (info->xmit_cnt >= ESP_XMIT_SIZE - 1) {
-               restore_flags(flags);
-               return;
+       spin_lock_irqsave(&info->lock, flags);
+       if (info->xmit_cnt < ESP_XMIT_SIZE - 1) {
+               info->xmit_buf[info->xmit_head++] = ch;
+               info->xmit_head &= ESP_XMIT_SIZE-1;
+               info->xmit_cnt++;
        }
-
-       info->xmit_buf[info->xmit_head++] = ch;
-       info->xmit_head &= ESP_XMIT_SIZE-1;
-       info->xmit_cnt++;
-       restore_flags(flags);
+       spin_unlock_irqrestore(&info->lock, flags);
 }
 
 static void rs_flush_chars(struct tty_struct *tty)
@@ -1251,19 +1232,21 @@ static void rs_flush_chars(struct tty_struct *tty)
        if (serial_paranoia_check(info, tty->name, "rs_flush_chars"))
                return;
 
+       spin_lock_irqsave(&info->lock, flags);
+
        if (info->xmit_cnt <= 0 || tty->stopped || !info->xmit_buf)
-               return;
+               goto out;
 
-       save_flags(flags); cli();
        if (!(info->IER & UART_IER_THRI)) {
                info->IER |= UART_IER_THRI;
                serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
                serial_out(info, UART_ESI_CMD2, info->IER);
        }
-       restore_flags(flags);
+out:
+       spin_unlock_irqrestore(&info->lock, flags);
 }
 
-static int rs_write(struct tty_struct * tty, int from_user,
+static int rs_write(struct tty_struct * tty,
                    const unsigned char *buf, int count)
 {
        int     c, t, ret = 0;
@@ -1273,12 +1256,9 @@ static int rs_write(struct tty_struct * tty, int from_user,
        if (serial_paranoia_check(info, tty->name, "rs_write"))
                return 0;
 
-       if (!tty || !info->xmit_buf || !tmp_buf)
+       if (!tty || !info->xmit_buf)
                return 0;
            
-       if (from_user)
-               down(&tmp_buf_sem);
-
        while (1) {
                /* Thanks to R. Wolff for suggesting how to do this with */
                /* interrupts enabled */
@@ -1297,18 +1277,7 @@ static int rs_write(struct tty_struct * tty, int from_user,
                if (c <= 0)
                        break;
 
-               if (from_user) {
-                       c -= copy_from_user(tmp_buf, buf, c);
-
-                       if (!c) {
-                               if (!ret)
-                                       ret = -EFAULT;
-                               break;
-                       }
-
-                       memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
-               } else
-                       memcpy(info->xmit_buf + info->xmit_head, buf, c);
+               memcpy(info->xmit_buf + info->xmit_head, buf, c);
 
                info->xmit_head = (info->xmit_head + c) & (ESP_XMIT_SIZE-1);
                info->xmit_cnt += c;
@@ -1317,10 +1286,7 @@ static int rs_write(struct tty_struct * tty, int from_user,
                ret += c;
        }
 
-       if (from_user)
-               up(&tmp_buf_sem);
-       
-       save_flags(flags); cli();
+       spin_lock_irqsave(&info->lock, flags);
 
        if (info->xmit_cnt && !tty->stopped && !(info->IER & UART_IER_THRI)) {
                info->IER |= UART_IER_THRI;
@@ -1328,7 +1294,7 @@ static int rs_write(struct tty_struct * tty, int from_user,
                serial_out(info, UART_ESI_CMD2, info->IER);
        }
 
-       restore_flags(flags);
+       spin_unlock_irqrestore(&info->lock, flags);
        return ret;
 }
 
@@ -1336,12 +1302,17 @@ static int rs_write_room(struct tty_struct *tty)
 {
        struct esp_struct *info = (struct esp_struct *)tty->driver_data;
        int     ret;
+       unsigned long flags;
                                
        if (serial_paranoia_check(info, tty->name, "rs_write_room"))
                return 0;
+
+       spin_lock_irqsave(&info->lock, flags);
+
        ret = ESP_XMIT_SIZE - info->xmit_cnt - 1;
        if (ret < 0)
                ret = 0;
+       spin_unlock_irqrestore(&info->lock, flags);
        return ret;
 }
 
@@ -1357,12 +1328,13 @@ static int rs_chars_in_buffer(struct tty_struct *tty)
 static void rs_flush_buffer(struct tty_struct *tty)
 {
        struct esp_struct *info = (struct esp_struct *)tty->driver_data;
+       unsigned long flags;
                                
        if (serial_paranoia_check(info, tty->name, "rs_flush_buffer"))
                return;
-       cli();
+       spin_lock_irqsave(&info->lock, flags);
        info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-       sti();
+       spin_unlock_irqrestore(&info->lock, flags);
        tty_wakeup(tty);
 }
 
@@ -1377,6 +1349,7 @@ static void rs_flush_buffer(struct tty_struct *tty)
 static void rs_throttle(struct tty_struct * tty)
 {
        struct esp_struct *info = (struct esp_struct *)tty->driver_data;
+       unsigned long flags;
 #ifdef SERIAL_DEBUG_THROTTLE
        char    buf[64];
        
@@ -1386,19 +1359,20 @@ static void rs_throttle(struct tty_struct * tty)
 
        if (serial_paranoia_check(info, tty->name, "rs_throttle"))
                return;
-       
-       cli();
+
+       spin_lock_irqsave(&info->lock, flags);
        info->IER &= ~UART_IER_RDI;
        serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
        serial_out(info, UART_ESI_CMD2, info->IER);
        serial_out(info, UART_ESI_CMD1, ESI_SET_RX_TIMEOUT);
        serial_out(info, UART_ESI_CMD2, 0x00);
-       sti();
+       spin_unlock_irqrestore(&info->lock, flags);
 }
 
 static void rs_unthrottle(struct tty_struct * tty)
 {
        struct esp_struct *info = (struct esp_struct *)tty->driver_data;
+       unsigned long flags;
 #ifdef SERIAL_DEBUG_THROTTLE
        char    buf[64];
        
@@ -1409,13 +1383,13 @@ static void rs_unthrottle(struct tty_struct * tty)
        if (serial_paranoia_check(info, tty->name, "rs_unthrottle"))
                return;
        
-       cli();
+       spin_lock_irqsave(&info->lock, flags);
        info->IER |= UART_IER_RDI;
        serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
        serial_out(info, UART_ESI_CMD2, info->IER);
        serial_out(info, UART_ESI_CMD1, ESI_SET_RX_TIMEOUT);
        serial_out(info, UART_ESI_CMD2, info->config.rx_timeout);
-       sti();
+       spin_unlock_irqrestore(&info->lock, flags);
 }
 
 /*
@@ -1588,6 +1562,7 @@ static int set_esp_config(struct esp_struct * info,
        unsigned int change_dma;
        int retval = 0;
        struct esp_struct *current_async;
+       unsigned long flags;
 
        /* Perhaps a non-sysadmin user should be able to do some of these */
        /* operations.  I haven't decided yet. */
@@ -1643,12 +1618,14 @@ static int set_esp_config(struct esp_struct * info,
                        
                         /* all ports must use the same DMA channel */
 
+                       spin_lock_irqsave(&info->lock, flags);
                        current_async = ports;
 
                        while (current_async) {
                                esp_basic_init(current_async);
                                current_async = current_async->next_port;
                        }
+                       spin_unlock_irqrestore(&info->lock, flags);
                } else {
                        /* DMA mode to PIO mode only */
                        
@@ -1656,8 +1633,10 @@ static int set_esp_config(struct esp_struct * info,
                                return -EBUSY;
 
                        shutdown(info);
+                       spin_lock_irqsave(&info->lock, flags);
                        info->stat_flags |= ESP_STAT_NEVER_DMA;
                        esp_basic_init(info);
+                       spin_unlock_irqrestore(&info->lock, flags);
                }
        }
 
@@ -1669,13 +1648,14 @@ static int set_esp_config(struct esp_struct * info,
 
                info->config.flow_off = new_config.flow_off;
                info->config.flow_on = new_config.flow_on;
-               save_flags(flags); cli();
+
+               spin_lock_irqsave(&info->lock, flags);
                serial_out(info, UART_ESI_CMD1, ESI_SET_FLOW_LVL);
                serial_out(info, UART_ESI_CMD2, new_config.flow_off >> 8);
                serial_out(info, UART_ESI_CMD2, new_config.flow_off);
                serial_out(info, UART_ESI_CMD2, new_config.flow_on >> 8);
                serial_out(info, UART_ESI_CMD2, new_config.flow_on);
-               restore_flags(flags);
+               spin_unlock_irqrestore(&info->lock, flags);
        }
 
        if ((new_config.rx_trigger != info->config.rx_trigger) ||
@@ -1684,7 +1664,7 @@ static int set_esp_config(struct esp_struct * info,
 
                info->config.rx_trigger = new_config.rx_trigger;
                info->config.tx_trigger = new_config.tx_trigger;
-               save_flags(flags); cli();
+               spin_lock_irqsave(&info->lock, flags);
                serial_out(info, UART_ESI_CMD1, ESI_SET_TRIGGER);
                serial_out(info, UART_ESI_CMD2,
                           new_config.rx_trigger >> 8);
@@ -1692,14 +1672,14 @@ static int set_esp_config(struct esp_struct * info,
                serial_out(info, UART_ESI_CMD2,
                           new_config.tx_trigger >> 8);
                serial_out(info, UART_ESI_CMD2, new_config.tx_trigger);
-               restore_flags(flags);
+               spin_unlock_irqrestore(&info->lock, flags);
        }
 
        if (new_config.rx_timeout != info->config.rx_timeout) {
                unsigned long flags;
 
                info->config.rx_timeout = new_config.rx_timeout;
-               save_flags(flags); cli();
+               spin_lock_irqsave(&info->lock, flags);
 
                if (info->IER & UART_IER_RDI) {
                        serial_out(info, UART_ESI_CMD1,
@@ -1708,7 +1688,7 @@ static int set_esp_config(struct esp_struct * info,
                                   new_config.rx_timeout);
                }
 
-               restore_flags(flags);
+               spin_unlock_irqrestore(&info->lock, flags);
        }
 
        if (!(info->flags & ASYNC_INITIALIZED))
@@ -1731,11 +1711,12 @@ static int get_lsr_info(struct esp_struct * info, unsigned int __user *value)
 {
        unsigned char status;
        unsigned int result;
+       unsigned long flags;
 
-       cli();
+       spin_lock_irqsave(&info->lock, flags);
        serial_out(info, UART_ESI_CMD1, ESI_GET_UART_STAT);
        status = serial_in(info, UART_ESI_STAT1);
-       sti();
+       spin_unlock_irqrestore(&info->lock, flags);
        result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
        return put_user(result,value);
 }
@@ -1745,6 +1726,7 @@ static int esp_tiocmget(struct tty_struct *tty, struct file *file)
 {
        struct esp_struct * info = (struct esp_struct *)tty->driver_data;
        unsigned char control, status;
+       unsigned long flags;
 
        if (serial_paranoia_check(info, tty->name, __FUNCTION__))
                return -ENODEV;
@@ -1752,10 +1734,12 @@ static int esp_tiocmget(struct tty_struct *tty, struct file *file)
                return -EIO;
 
        control = info->MCR;
-       cli();
+
+       spin_lock_irqsave(&info->lock, flags);
        serial_out(info, UART_ESI_CMD1, ESI_GET_UART_STAT);
        status = serial_in(info, UART_ESI_STAT2);
-       sti();
+       spin_unlock_irqrestore(&info->lock, flags);
+
        return    ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
                | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
                | ((status  & UART_MSR_DCD) ? TIOCM_CAR : 0)
@@ -1768,13 +1752,14 @@ static int esp_tiocmset(struct tty_struct *tty, struct file *file,
                        unsigned int set, unsigned int clear)
 {
        struct esp_struct * info = (struct esp_struct *)tty->driver_data;
+       unsigned long flags;
 
        if (serial_paranoia_check(info, tty->name, __FUNCTION__))
                return -ENODEV;
        if (tty->flags & (1 << TTY_IO_ERROR))
                return -EIO;
 
-       cli();
+       spin_lock_irqsave(&info->lock, flags);
 
        if (set & TIOCM_RTS)
                info->MCR |= UART_MCR_RTS;
@@ -1789,7 +1774,8 @@ static int esp_tiocmset(struct tty_struct *tty, struct file *file,
        serial_out(info, UART_ESI_CMD1, ESI_WRITE_UART);
        serial_out(info, UART_ESI_CMD2, UART_MCR);
        serial_out(info, UART_ESI_CMD2, info->MCR);
-       sti();
+
+       spin_unlock_irqrestore(&info->lock, flags);
        return 0;
 }
 
@@ -1804,17 +1790,20 @@ static void esp_break(struct tty_struct *tty, int break_state)
        if (serial_paranoia_check(info, tty->name, "esp_break"))
                return;
 
-       save_flags(flags); cli();
        if (break_state == -1) {
+               spin_lock_irqsave(&info->lock, flags);
                serial_out(info, UART_ESI_CMD1, ESI_ISSUE_BREAK);
                serial_out(info, UART_ESI_CMD2, 0x01);
+               spin_unlock_irqrestore(&info->lock, flags);
 
+               /* FIXME - new style wait needed here */
                interruptible_sleep_on(&info->break_wait);
        } else {
+               spin_lock_irqsave(&info->lock, flags);
                serial_out(info, UART_ESI_CMD1, ESI_ISSUE_BREAK);
                serial_out(info, UART_ESI_CMD2, 0x00);
+               spin_unlock_irqrestore(&info->lock, flags);
        }
-       restore_flags(flags);
 }
 
 static int rs_ioctl(struct tty_struct *tty, struct file * file,
@@ -1824,6 +1813,7 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
        struct async_icount cprev, cnow;        /* kernel counter temps */
        struct serial_icounter_struct __user *p_cuser;  /* user space */
        void __user *argp = (void __user *)arg;
+       unsigned long flags;
 
        if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
                return -ENODEV;
@@ -1864,17 +1854,18 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
                 * Caller should use TIOCGICOUNT to see which one it was
                 */
                 case TIOCMIWAIT:
-                       cli();
+                       spin_lock_irqsave(&info->lock, flags);
                        cprev = info->icount;   /* note the counters on entry */
-                       sti();
+                       spin_unlock_irqrestore(&info->lock, flags);
                        while (1) {
+                               /* FIXME: convert to new style wakeup */
                                interruptible_sleep_on(&info->delta_msr_wait);
                                /* see if a signal did it */
                                if (signal_pending(current))
                                        return -ERESTARTSYS;
-                               cli();
+                               spin_lock_irqsave(&info->lock, flags);
                                cnow = info->icount;    /* atomic copy */
-                               sti();
+                               spin_unlock_irqrestore(&info->lock, flags);
                                if (cnow.rng == cprev.rng &&
                                    cnow.dsr == cprev.dsr && 
                                    cnow.dcd == cprev.dcd &&
@@ -1901,9 +1892,9 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
                 *     RI where only 0->1 is counted.
                 */
                case TIOCGICOUNT:
-                       cli();
+                       spin_lock_irqsave(&info->lock, flags);
                        cnow = info->icount;
-                       sti();
+                       spin_unlock_irqrestore(&info->lock, flags);
                        p_cuser = argp;
                        if (put_user(cnow.cts, &p_cuser->cts) ||
                            put_user(cnow.dsr, &p_cuser->dsr) ||
@@ -1926,53 +1917,42 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
 static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
 {
        struct esp_struct *info = (struct esp_struct *)tty->driver_data;
+       unsigned long flags;
 
        if (   (tty->termios->c_cflag == old_termios->c_cflag)
            && (   RELEVANT_IFLAG(tty->termios->c_iflag) 
                == RELEVANT_IFLAG(old_termios->c_iflag)))
-         return;
+               return;
 
        change_speed(info);
 
+       spin_lock_irqsave(&info->lock, flags);
+
        /* Handle transition to B0 status */
        if ((old_termios->c_cflag & CBAUD) &&
                !(tty->termios->c_cflag & CBAUD)) {
                info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
-               cli();
                serial_out(info, UART_ESI_CMD1, ESI_WRITE_UART);
                serial_out(info, UART_ESI_CMD2, UART_MCR);
                serial_out(info, UART_ESI_CMD2, info->MCR);
-               sti();
        }
 
        /* Handle transition away from B0 status */
        if (!(old_termios->c_cflag & CBAUD) &&
                (tty->termios->c_cflag & CBAUD)) {
                info->MCR |= (UART_MCR_DTR | UART_MCR_RTS);
-               cli();
                serial_out(info, UART_ESI_CMD1, ESI_WRITE_UART);
                serial_out(info, UART_ESI_CMD2, UART_MCR);
                serial_out(info, UART_ESI_CMD2, info->MCR);
-               sti();
        }
 
+       spin_unlock_irqrestore(&info->lock, flags);
+
        /* Handle turning of CRTSCTS */
        if ((old_termios->c_cflag & CRTSCTS) &&
            !(tty->termios->c_cflag & CRTSCTS)) {
                rs_start(tty);
        }
-
-#if 0
-       /*
-        * No need to wake up processes in open wait, since they
-        * sample the CLOCAL flag once, and don't recheck it.
-        * XXX  It's not clear whether the current behavior is correct
-        * or not.  Hence, this may change.....
-        */
-       if (!(old_termios->c_cflag & CLOCAL) &&
-           (tty->termios->c_cflag & CLOCAL))
-               wake_up_interruptible(&info->open_wait);
-#endif
 }
 
 /*
@@ -1993,7 +1973,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
        if (!info || serial_paranoia_check(info, tty->name, "rs_close"))
                return;
        
-       save_flags(flags); cli();
+       spin_lock_irqsave(&info->lock, flags);
        
        if (tty_hung_up_p(filp)) {
                DBG_CNT("before DEC-hung");
@@ -2025,6 +2005,8 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
                goto out;
        }
        info->flags |= ASYNC_CLOSING;
+
+       spin_unlock_irqrestore(&info->lock, flags);
        /*
         * Now we wait for the transmit buffer to clear; and we notify 
         * the line discipline to only process XON/XOFF characters.
@@ -2042,6 +2024,8 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
        info->IER &= ~UART_IER_RDI;
        info->read_status_mask &= ~UART_LSR_DR;
        if (info->flags & ASYNC_INITIALIZED) {
+
+               spin_lock_irqsave(&info->lock, flags);
                serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
                serial_out(info, UART_ESI_CMD2, info->IER);
 
@@ -2049,6 +2033,8 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
                serial_out(info, UART_ESI_CMD1, ESI_SET_RX_TIMEOUT);
                serial_out(info, UART_ESI_CMD2, 0x00);
 
+               spin_unlock_irqrestore(&info->lock, flags);
+
                /*
                 * Before we drop DTR, make sure the UART transmitter
                 * has completely drained; this is especially
@@ -2066,15 +2052,16 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
 
        if (info->blocked_open) {
                if (info->close_delay) {
-                       set_current_state(TASK_INTERRUPTIBLE);
-                       schedule_timeout(info->close_delay);
+                       msleep_interruptible(jiffies_to_msecs(info->close_delay));
                }
                wake_up_interruptible(&info->open_wait);
        }
        info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
        wake_up_interruptible(&info->close_wait);
+       return;
+
 out:
-       restore_flags(flags);
+       spin_unlock_irqrestore(&info->lock, flags);
 }
 
 static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
@@ -2092,14 +2079,15 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
        if (!char_time)
                char_time = 1;
 
-       save_flags(flags); cli();
+       spin_lock_irqsave(&info->lock, flags);
        serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND);
        serial_out(info, UART_ESI_CMD1, ESI_GET_TX_AVAIL);
 
        while ((serial_in(info, UART_ESI_STAT1) != 0x03) ||
                (serial_in(info, UART_ESI_STAT2) != 0xff)) {
-               set_current_state(TASK_INTERRUPTIBLE);
-               schedule_timeout(char_time);
+
+               spin_unlock_irqrestore(&info->lock, flags);
+               msleep_interruptible(jiffies_to_msecs(char_time));
 
                if (signal_pending(current))
                        break;
@@ -2107,11 +2095,11 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
                if (timeout && time_after(jiffies, orig_jiffies + timeout))
                        break;
 
+               spin_lock_irqsave(&info->lock, flags);
                serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND);
                serial_out(info, UART_ESI_CMD1, ESI_GET_TX_AVAIL);
        }
-       
-       restore_flags(flags);
+       spin_unlock_irqrestore(&info->lock, flags);
        set_current_state(TASK_RUNNING);
 }
 
@@ -2191,15 +2179,11 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
        printk("block_til_ready before block: ttys%d, count = %d\n",
               info->line, info->count);
 #endif
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&info->lock, flags);
        if (!tty_hung_up_p(filp)) 
                info->count--;
-       restore_flags(flags);
        info->blocked_open++;
        while (1) {
-               save_flags(flags);
-               cli();
                if ((tty->termios->c_cflag & CBAUD)) {
                        unsigned int scratch;
 
@@ -2211,7 +2195,6 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
                        serial_out(info, UART_ESI_CMD2,
                                scratch | UART_MCR_DTR | UART_MCR_RTS);
                }
-               restore_flags(flags);
                set_current_state(TASK_INTERRUPTIBLE);
                if (tty_hung_up_p(filp) ||
                    !(info->flags & ASYNC_INITIALIZED)) {
@@ -2241,13 +2224,16 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
                printk("block_til_ready blocking: ttys%d, count = %d\n",
                       info->line, info->count);
 #endif
+               spin_unlock_irqrestore(&info->lock, flags);
                schedule();
+               spin_lock_irqsave(&info->lock, flags);
        }
        set_current_state(TASK_RUNNING);
        remove_wait_queue(&info->open_wait, &wait);
        if (!tty_hung_up_p(filp))
                info->count++;
        info->blocked_open--;
+       spin_unlock_irqrestore(&info->lock, flags);
 #ifdef SERIAL_DEBUG_OPEN
        printk("block_til_ready after blocking: ttys%d, count = %d\n",
               info->line, info->count);
@@ -2268,6 +2254,7 @@ static int esp_open(struct tty_struct *tty, struct file * filp)
 {
        struct esp_struct       *info;
        int                     retval, line;
+       unsigned long           flags;
 
        line = tty->index;
        if ((line < 0) || (line >= NR_PORTS))
@@ -2288,15 +2275,12 @@ static int esp_open(struct tty_struct *tty, struct file * filp)
 #ifdef SERIAL_DEBUG_OPEN
        printk("esp_open %s, count = %d\n", tty->name, info->count);
 #endif
+       spin_lock_irqsave(&info->lock, flags);
        info->count++;
        tty->driver_data = info;
        info->tty = tty;
 
-       if (!tmp_buf) {
-               tmp_buf = (unsigned char *) get_zeroed_page(GFP_KERNEL);
-               if (!tmp_buf)
-                       return -ENOMEM;
-       }
+       spin_unlock_irqrestore(&info->lock, flags);
        
        /*
         * Start up serial port
@@ -2334,7 +2318,7 @@ static int esp_open(struct tty_struct *tty, struct file * filp)
  * driver.
  */
  
-static _INLINE_ void show_serial_version(void)
+static inline void show_serial_version(void)
 {
        printk(KERN_INFO "%s version %s (DMA %u)\n",
                serial_name, serial_version, dma);
@@ -2344,19 +2328,20 @@ static _INLINE_ void show_serial_version(void)
  * This routine is called by espserial_init() to initialize a specific serial
  * port.
  */
-static _INLINE_ int autoconfig(struct esp_struct * info, int *region_start)
+static inline int autoconfig(struct esp_struct * info)
 {
        int port_detected = 0;
        unsigned long flags;
 
-       save_flags(flags); cli();
-       
+       if (!request_region(info->port, REGION_SIZE, "esp serial"))
+               return -EIO;
+
+       spin_lock_irqsave(&info->lock, flags);
        /*
         * Check for ESP card
         */
 
-       if (!check_region(info->port, 8) && 
-           serial_in(info, UART_ESI_BASE) == 0xf3) {
+       if (serial_in(info, UART_ESI_BASE) == 0xf3) {
                serial_out(info, UART_ESI_CMD1, 0x00);
                serial_out(info, UART_ESI_CMD1, 0x01);
 
@@ -2372,19 +2357,6 @@ static _INLINE_ int autoconfig(struct esp_struct * info, int *region_start)
                                        info->irq = 4;
                        }
 
-                       if (ports && (ports->port == (info->port - 8))) {
-                               release_region(*region_start,
-                                              info->port - *region_start);
-                       } else
-                               *region_start = info->port;
-
-                       if (!request_region(*region_start,
-                                      info->port - *region_start + 8,
-                                      "esp serial"))
-                       {
-                               restore_flags(flags);
-                               return -EIO;
-                       }
 
                        /* put card in enhanced mode */
                        /* this prevents access through */
@@ -2397,8 +2369,10 @@ static _INLINE_ int autoconfig(struct esp_struct * info, int *region_start)
                        serial_out(info, UART_ESI_CMD2, 0x00);
                }
        }
+       if (!port_detected)
+               release_region(info->port, REGION_SIZE);
 
-       restore_flags(flags);
+       spin_unlock_irqrestore(&info->lock, flags);
        return (port_detected);
 }
 
@@ -2427,10 +2401,9 @@ static struct tty_operations esp_ops = {
 /*
  * The serial driver boot-time initialization code!
  */
-int __init espserial_init(void)
+static int __init espserial_init(void)
 {
        int i, offset;
-       int region_start;
        struct esp_struct * info;
        struct esp_struct *last_primary = NULL;
        int esp[] = {0x100,0x140,0x180,0x200,0x240,0x280,0x300,0x380};
@@ -2504,6 +2477,7 @@ int __init espserial_init(void)
        }
 
        memset((void *)info, 0, sizeof(struct esp_struct));
+       spin_lock_init(&info->lock);
        /* rx_trigger, tx_trigger are needed by autoconfig */
        info->config.rx_trigger = rx_trigger;
        info->config.tx_trigger = tx_trigger;
@@ -2516,7 +2490,7 @@ int __init espserial_init(void)
                info->irq = irq[i];
                info->line = (i * 8) + (offset / 8);
 
-               if (!autoconfig(info, &region_start)) {
+               if (!autoconfig(info)) {
                        i++;
                        offset = 0;
                        continue;
@@ -2590,44 +2564,20 @@ int __init espserial_init(void)
 
 static void __exit espserial_exit(void) 
 {
-       unsigned long flags;
        int e1;
-       unsigned int region_start, region_end;
        struct esp_struct *temp_async;
        struct esp_pio_buffer *pio_buf;
 
        /* printk("Unloading %s: version %s\n", serial_name, serial_version); */
-       save_flags(flags);
-       cli();
        if ((e1 = tty_unregister_driver(esp_driver)))
                printk("SERIAL: failed to unregister serial driver (%d)\n",
                       e1);
-       restore_flags(flags);
        put_tty_driver(esp_driver);
 
        while (ports) {
                if (ports->port) {
-                       region_start = region_end = ports->port;
-                       temp_async = ports;
-
-                       while (temp_async) {
-                               if ((region_start - temp_async->port) == 8) {
-                                       region_start = temp_async->port;
-                                       temp_async->port = 0;
-                                       temp_async = ports;
-                               } else if ((temp_async->port - region_end)
-                                          == 8) {
-                                       region_end = temp_async->port;
-                                       temp_async->port = 0;
-                                       temp_async = ports;
-                               } else
-                                       temp_async = temp_async->next_port;
-                       }
-                       
-                       release_region(region_start,
-                                      region_end - region_start + 8);
+                       release_region(ports->port, REGION_SIZE);
                }
-
                temp_async = ports->next_port;
                kfree(ports);
                ports = temp_async;
@@ -2637,9 +2587,6 @@ static void __exit espserial_exit(void)
                free_pages((unsigned long)dma_buffer,
                        get_order(DMA_BUFFER_SZ));
 
-       if (tmp_buf)
-               free_page((unsigned long)tmp_buf);
-
        while (free_pio_buf) {
                pio_buf = free_pio_buf->next;
                kfree(free_pio_buf);