]> git.karo-electronics.de Git - linux-beck.git/commitdiff
Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 11 Dec 2009 23:34:40 +0000 (15:34 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 11 Dec 2009 23:34:40 +0000 (15:34 -0800)
* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty-2.6: (58 commits)
  tty: split the lock up a bit further
  tty: Move the leader test in disassociate
  tty: Push the bkl down a bit in the hangup code
  tty: Push the lock down further into the ldisc code
  tty: push the BKL down into the handlers a bit
  tty: moxa: split open lock
  tty: moxa: Kill the use of lock_kernel
  tty: moxa: Fix modem op locking
  tty: moxa: Kill off the throttle method
  tty: moxa: Locking clean up
  tty: moxa: rework the locking a bit
  tty: moxa: Use more tty_port ops
  tty: isicom: fix deadlock on shutdown
  tty: mxser: Use the new locking rules to fix setserial properly
  tty: mxser: use the tty_port_open method
  tty: isicom: sort out the board init logic
  tty: isicom: switch to the new tty_port_open helper
  tty: tty_port: Add a kref object to the tty port
  tty: istallion: tty port open/close methods
  tty: stallion: Convert to the tty_port_open/close methods
  ...

36 files changed:
Documentation/serial/hayes-esp.txt [deleted file]
Documentation/serial/tty.txt
arch/xtensa/platforms/iss/console.c
drivers/char/Kconfig
drivers/char/Makefile
drivers/char/bfin_jtag_comm.c
drivers/char/epca.c
drivers/char/esp.c [deleted file]
drivers/char/isicom.c
drivers/char/istallion.c
drivers/char/moxa.c
drivers/char/mxser.c
drivers/char/pcmcia/ipwireless/tty.c
drivers/char/pty.c
drivers/char/riscom8.c
drivers/char/stallion.c
drivers/char/tty_io.c
drivers/char/tty_ldisc.c
drivers/char/tty_port.c
drivers/mmc/card/sdio_uart.c
drivers/serial/8250.c
drivers/serial/jsm/jsm.h
drivers/serial/jsm/jsm_driver.c
drivers/serial/jsm/jsm_neo.c
drivers/serial/jsm/jsm_tty.c
drivers/serial/pxa.c
drivers/serial/serial_core.c
drivers/usb/serial/opticon.c
drivers/usb/serial/usb-serial.c
fs/devpts/inode.c
include/linux/Kbuild
include/linux/hayesesp.h [deleted file]
include/linux/isicom.h
include/linux/tty.h
include/linux/usb/serial.h
kernel/exit.c

diff --git a/Documentation/serial/hayes-esp.txt b/Documentation/serial/hayes-esp.txt
deleted file mode 100644 (file)
index 09b5d58..0000000
+++ /dev/null
@@ -1,154 +0,0 @@
-HAYES ESP DRIVER VERSION 2.1
-
-A big thanks to the people at Hayes, especially Alan Adamson.  Their support
-has enabled me to provide enhancements to the driver.
-
-Please report your experiences with this driver to me (arobinso@nyx.net).  I
-am looking for both positive and negative feedback.
-
-*** IMPORTANT CHANGES FOR 2.1 ***
-Support for PIO mode.  Five situations will cause PIO mode to be used:
-1) A multiport card is detected.  PIO mode will always be used.  (8 port cards
-do not support DMA).
-2) The DMA channel is set to an invalid value (anything other than 1 or 3).
-3) The DMA buffer/channel could not be allocated.  The port will revert to PIO
-mode until it is reopened.
-4) Less than a specified number of bytes need to be transferred to/from the
-FIFOs.  PIO mode will be used for that transfer only.
-5) A port needs to do a DMA transfer and another port is already using the
-DMA channel.  PIO mode will be used for that transfer only.
-
-Since the Hayes ESP seems to conflict with other cards (notably sound cards)
-when using DMA, DMA is turned off by default.  To use DMA, it must be turned
-on explicitly, either with the "dma=" option described below or with
-setserial.  A multiport card can be forced into DMA mode by using setserial;
-however, most multiport cards don't support DMA.
-
-The latest version of setserial allows the enhanced configuration of the ESP
-card to be viewed and modified.
-***
-
-This package contains the files needed to compile a module to support the Hayes
-ESP card.  The drivers are basically a modified version of the serial drivers.
-
-Features:
-
-- Uses the enhanced mode of the ESP card, allowing a wider range of
-  interrupts and features than compatibility mode
-- Uses DMA and 16 bit PIO mode to transfer data to and from the ESP's FIFOs,
-  reducing CPU load
-- Supports primary and secondary ports
-
-
-If the driver is compiled as a module, the IRQs to use can be specified by
-using the irq= option.  The format is:
-
-irq=[0x100],[0x140],[0x180],[0x200],[0x240],[0x280],[0x300],[0x380]
-
-The address in brackets is the base address of the card.  The IRQ of
-nonexistent cards can be set to 0.  If an IRQ of a card that does exist is set
-to 0, the driver will attempt to guess at the correct IRQ.  For example, to set
-the IRQ of the card at address 0x300 to 12, the insmod command would be:
-
-insmod esp irq=0,0,0,0,0,0,12,0
-
-The custom divisor can be set by using the divisor= option.  The format is the
-same as for the irq= option.  Each divisor value is a series of hex digits,
-with each digit representing the divisor to use for a corresponding port.  The
-divisor value is constructed RIGHT TO LEFT.  Specifying a nonzero divisor value
-will automatically set the spd_cust flag.  To calculate the divisor to use for
-a certain baud rate, divide the port's base baud (generally 921600) by the
-desired rate.  For example, to set the divisor of the primary port at 0x300 to
-4 and the divisor of the secondary port at 0x308 to 8, the insmod command would
-be:
-
-insmod esp divisor=0,0,0,0,0,0,0x84,0
-
-The dma= option can be used to set the DMA channel.  The channel can be either
-1 or 3.  Specifying any other value will force the driver to use PIO mode.
-For example, to set the DMA channel to 3, the insmod command would be:
-
-insmod esp dma=3
-
-The rx_trigger= and tx_trigger= options can be used to set the FIFO trigger
-levels.  They specify when the ESP card should send an interrupt.  Larger
-values will decrease the number of interrupts; however, a value too high may
-result in data loss.  Valid values are 1 through 1023, with 768 being the
-default.  For example, to set the receive trigger level to 512 bytes and the
-transmit trigger level to 700 bytes, the insmod command would be:
-
-insmod esp rx_trigger=512 tx_trigger=700
-
-The flow_off= and flow_on= options can be used to set the hardware flow off/
-flow on levels.  The flow on level must be lower than the flow off level, and
-the flow off level should be higher than rx_trigger.  Valid values are 1
-through 1023, with 1016 being the default flow off level and 944 being the
-default flow on level.  For example, to set the flow off level to 1000 bytes
-and the flow on level to 935 bytes, the insmod command would be:
-
-insmod esp flow_off=1000 flow_on=935
-
-The rx_timeout= option can be used to set the receive timeout value.  This
-value indicates how long after receiving the last character that the ESP card
-should wait before signalling an interrupt.  Valid values are 0 though 255,
-with 128 being the default.  A value too high will increase latency, and a
-value too low will cause unnecessary interrupts.  For example, to set the
-receive timeout to 255, the insmod command would be:
-
-insmod esp rx_timeout=255
-
-The pio_threshold= option sets the threshold (in number of characters) for
-using PIO mode instead of DMA mode.  For example, if this value is 32,
-transfers of 32 bytes or less will always use PIO mode.
-
-insmod esp pio_threshold=32
-
-Multiple options can be listed on the insmod command line by separating each
-option with a space.  For example:
-
-insmod esp dma=3 trigger=512
-
-The esp module can be automatically loaded when needed.  To cause this to
-happen, add the following lines to /etc/modprobe.conf (replacing the last line
-with options for your configuration):
-
-alias char-major-57 esp
-alias char-major-58 esp
-options esp irq=0,0,0,0,0,0,3,0 divisor=0,0,0,0,0,0,0x4,0
-
-You may also need to run 'depmod -a'.
-
-Devices must be created manually.  To create the devices, note the output from
-the module after it is inserted.  The output will appear in the location where
-kernel messages usually appear (usually /var/adm/messages).  Create two devices
-for each 'tty' mentioned, one with major of 57 and the other with major of 58.
-The minor number should be the same as the tty number reported.  The commands
-would be (replace ? with the tty number):
-
-mknod /dev/ttyP? c 57 ?
-mknod /dev/cup? c 58 ?
-
-For example, if the following line appears:
-
-Oct 24 18:17:23 techno kernel: ttyP8 at 0x0140 (irq = 3) is an ESP primary port
-
-...two devices should be created:
-
-mknod /dev/ttyP8 c 57 8
-mknod /dev/cup8 c 58 8
-
-You may need to set the permissions on the devices:
-
-chmod 666 /dev/ttyP*
-chmod 666 /dev/cup*
-
-The ESP module and the serial module should not conflict (they can be used at
-the same time).  After the ESP module has been loaded the ports on the ESP card
-will no longer be accessible by the serial driver.
-
-If I/O errors are experienced when accessing the port, check for IRQ and DMA
-conflicts ('cat /proc/interrupts' and 'cat /proc/dma' for a list of IRQs and
-DMAs currently in use).
-
-Enjoy!
-Andrew J. Robinson <arobinso@nyx.net>
index 8e65c4498c521259d93061e0a94a2d3652eaef98..5e5349a4fcd281b2450415d7d668456aedd34b4b 100644 (file)
@@ -42,7 +42,8 @@ TTY side interfaces:
 open()         -       Called when the line discipline is attached to
                        the terminal. No other call into the line
                        discipline for this tty will occur until it
-                       completes successfully. Can sleep.
+                       completes successfully. Returning an error will
+                       prevent the ldisc from being attached. Can sleep.
 
 close()                -       This is called on a terminal when the line
                        discipline is being unplugged. At the point of
@@ -52,7 +53,7 @@ close()               -       This is called on a terminal when the line
 hangup()       -       Called when the tty line is hung up.
                        The line discipline should cease I/O to the tty.
                        No further calls into the ldisc code will occur.
-                       Can sleep.
+                       The return value is ignored. Can sleep.
 
 write()                -       A process is writing data through the line
                        discipline.  Multiple write calls are serialized
@@ -83,6 +84,10 @@ ioctl()              -       Called when an ioctl is handed to the tty layer
                        that might be for the ldisc. Multiple ioctl calls
                        may occur in parallel. May sleep. 
 
+compat_ioctl() -       Called when a 32 bit ioctl is handed to the tty layer
+                       that might be for the ldisc. Multiple ioctl calls
+                       may occur in parallel. May sleep.
+
 Driver Side Interfaces:
 
 receive_buf()  -       Hand buffers of bytes from the driver to the ldisc
index 4c559cf7da2d8c13c0a0529f5ae2e458b65257d1..e60a1f57022f358a6ca1e61119ed8e71f547bcbf 100644 (file)
@@ -196,7 +196,7 @@ static const struct file_operations rs_proc_fops = {
        .release        = single_release,
 };
 
-static struct tty_operations serial_ops = {
+static const struct tty_operations serial_ops = {
        .open = rs_open,
        .close = rs_close,
        .write = rs_write,
index 6aad99ec4e0f12626038c0d93c0a025b4d7d4b4d..6f31c947210093c756d0b516dbf5743f1b7a0c84 100644 (file)
@@ -201,19 +201,6 @@ config DIGIEPCA
          To compile this driver as a module, choose M here: the
          module will be called epca.
 
-config ESPSERIAL
-       tristate "Hayes ESP serial port support"
-       depends on SERIAL_NONSTANDARD && ISA && ISA_DMA_API && BROKEN
-       help
-         This is a driver which supports Hayes ESP serial ports.  Both single
-         port cards and multiport cards are supported.  Make sure to read
-         <file:Documentation/hayes-esp.txt>.
-
-         To compile this driver as a module, choose M here: the
-         module will be called esp.
-
-         If unsure, say N.
-
 config MOXA_INTELLIO
        tristate "Moxa Intellio support"
        depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI)
index 19a79dd79eee0008503552ac41a14881205d87cd..f957edf7e45d2074bff77e2ac49a7edbe64cd98b 100644 (file)
@@ -18,7 +18,6 @@ obj-$(CONFIG_CONSOLE_TRANSLATIONS) += consolemap.o consolemap_deftbl.o
 obj-$(CONFIG_HW_CONSOLE)       += vt.o defkeymap.o
 obj-$(CONFIG_AUDIT)            += tty_audit.o
 obj-$(CONFIG_MAGIC_SYSRQ)      += sysrq.o
-obj-$(CONFIG_ESPSERIAL)                += esp.o
 obj-$(CONFIG_MVME147_SCC)      += generic_serial.o vme_scc.o
 obj-$(CONFIG_MVME162_SCC)      += generic_serial.o vme_scc.o
 obj-$(CONFIG_BVME6000_SCC)     += generic_serial.o vme_scc.o
index 1d7c34c73b202594467bdac85fde9f634fdfc552..2628c7415ea863b07b0caa5064bbf0c0c42f3dfb 100644 (file)
@@ -226,7 +226,7 @@ bfin_jc_wait_until_sent(struct tty_struct *tty, int timeout)
        }
 }
 
-static struct tty_operations bfin_jc_ops = {
+static const struct tty_operations bfin_jc_ops = {
        .open            = bfin_jc_open,
        .close           = bfin_jc_close,
        .write           = bfin_jc_write,
index dde5134713e23f88fe185e2f4216cd9ad62ebfac..17b044a71e026fc8c943de8ea5bf64c852abc75c 100644 (file)
@@ -935,7 +935,7 @@ static int info_open(struct tty_struct *tty, struct file *filp)
        return 0;
 }
 
-static struct tty_operations info_ops = {
+static const struct tty_operations info_ops = {
        .open = info_open,
        .ioctl = info_ioctl,
 };
diff --git a/drivers/char/esp.c b/drivers/char/esp.c
deleted file mode 100644 (file)
index b19d43c..0000000
+++ /dev/null
@@ -1,2533 +0,0 @@
-/*
- *  esp.c - driver for Hayes ESP serial cards
- *
- *  --- Notices from serial.c, upon which this driver is based ---
- *
- *  Copyright (C) 1991, 1992  Linus Torvalds
- *
- *  Extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92.  Now
- *  much more extensible to support other serial cards based on the
- *  16450/16550A UART's.  Added support for the AST FourPort and the
- *  Accent Async board.
- *
- *  set_serial_info fixed to set the flags, custom divisor, and uart
- *     type fields.  Fix suggested by Michael K. Johnson 12/12/92.
- *
- *  11/95: TIOCMIWAIT, TIOCGICOUNT by Angelo Haritsis <ah@doc.ic.ac.uk>
- *
- *  03/96: Modularised by Angelo Haritsis <ah@doc.ic.ac.uk>
- *
- *  rs_set_termios fixed to look also for changes of the input
- *      flags INPCK, BRKINT, PARMRK, IGNPAR and IGNBRK.
- *                                            Bernd Anhäupl 05/17/96.
- *
- * --- End of notices from serial.c ---
- *
- * Support for the ESP serial card by Andrew J. Robinson
- *     <arobinso@nyx.net> (Card detection routine taken from a patch
- *     by Dennis J. Boylan).  Patches to allow use with 2.1.x contributed
- *     by Chris Faylor.
- *
- * Most recent changes: (Andrew J. Robinson)
- *   Support for PIO mode.  This allows the driver to work properly with
- *     multiport cards.
- *
- * Arnaldo Carvalho de Melo <acme@conectiva.com.br> -
- * several cleanups, use module_init/module_exit, etc
- *
- * This module exports the following rs232 io functions:
- *
- *     int espserial_init(void);
- */
-
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial.h>
-#include <linux/serialP.h>
-#include <linux/serial_reg.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/ptrace.h>
-#include <linux/ioport.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/bitops.h>
-
-#include <asm/system.h>
-#include <linux/io.h>
-
-#include <asm/dma.h>
-#include <linux/slab.h>
-#include <linux/uaccess.h>
-
-#include <linux/hayesesp.h>
-
-#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 */
-static unsigned int divisor[NR_PRIMARY]; /* custom divisor for each port */
-static unsigned int dma = ESP_DMA_CHANNEL; /* DMA channel */
-static unsigned int rx_trigger = ESP_RX_TRIGGER;
-static unsigned int tx_trigger = ESP_TX_TRIGGER;
-static unsigned int flow_off = ESP_FLOW_OFF;
-static unsigned int flow_on = ESP_FLOW_ON;
-static unsigned int rx_timeout = ESP_RX_TMOUT;
-static unsigned int pio_threshold = ESP_PIO_THRESHOLD;
-
-MODULE_LICENSE("GPL");
-
-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 */
-
-static char *dma_buffer;
-static int dma_bytes;
-static struct esp_pio_buffer *free_pio_buf;
-
-#define DMA_BUFFER_SZ 1024
-
-#define WAKEUP_CHARS 1024
-
-static char serial_name[] __initdata = "ESP serial driver";
-static char serial_version[] __initdata = "2.2";
-
-static struct tty_driver *esp_driver;
-
-/*
- * Serial driver configuration section.  Here are the various options:
- *
- * SERIAL_PARANOIA_CHECK
- *             Check the magic number for the esp_structure where
- *             ever possible.
- */
-
-#undef SERIAL_PARANOIA_CHECK
-#define SERIAL_DO_RESTART
-
-#undef SERIAL_DEBUG_INTR
-#undef SERIAL_DEBUG_OPEN
-#undef SERIAL_DEBUG_FLOW
-
-#if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT)
-#define DBG_CNT(s) printk(KERN_DEBUG "(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \
-                               tty->name, info->port.flags, \
-                               serial_driver.refcount, \
-                               info->port.count, tty->count, s)
-#else
-#define DBG_CNT(s)
-#endif
-
-static struct esp_struct *ports;
-
-static void change_speed(struct esp_struct *info);
-static void rs_wait_until_sent(struct tty_struct *, int);
-
-/*
- * The ESP card has a clock rate of 14.7456 MHz (that is, 2**ESPC_SCALE
- * times the normal 1.8432 Mhz clock of most serial boards).
- */
-#define BASE_BAUD ((1843200 / 16) * (1 << ESPC_SCALE))
-
-/* Standard COM flags (except for COM4, because of the 8514 problem) */
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
-
-static inline int serial_paranoia_check(struct esp_struct *info,
-                                       char *name, const char *routine)
-{
-#ifdef SERIAL_PARANOIA_CHECK
-       static const char badmagic[] = KERN_WARNING
-               "Warning: bad magic number for serial struct (%s) in %s\n";
-       static const char badinfo[] = KERN_WARNING
-               "Warning: null esp_struct for (%s) in %s\n";
-
-       if (!info) {
-               printk(badinfo, name, routine);
-               return 1;
-       }
-       if (info->magic != ESP_MAGIC) {
-               printk(badmagic, name, routine);
-               return 1;
-       }
-#endif
-       return 0;
-}
-
-static inline unsigned int serial_in(struct esp_struct *info, int offset)
-{
-       return inb(info->io_port + offset);
-}
-
-static inline void serial_out(struct esp_struct *info, int offset,
-                             unsigned char value)
-{
-       outb(value, info->io_port+offset);
-}
-
-/*
- * ------------------------------------------------------------
- * rs_stop() and rs_start()
- *
- * This routines are called before setting or resetting tty->stopped.
- * They enable or disable transmitter interrupts, as necessary.
- * ------------------------------------------------------------
- */
-static void rs_stop(struct tty_struct *tty)
-{
-       struct esp_struct *info = tty->driver_data;
-       unsigned long flags;
-
-       if (serial_paranoia_check(info, tty->name, "rs_stop"))
-               return;
-
-       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);
-       }
-       spin_unlock_irqrestore(&info->lock, flags);
-}
-
-static void rs_start(struct tty_struct *tty)
-{
-       struct esp_struct *info = tty->driver_data;
-       unsigned long flags;
-
-       if (serial_paranoia_check(info, tty->name, "rs_start"))
-               return;
-
-       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);
-       }
-       spin_unlock_irqrestore(&info->lock, flags);
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * Here starts the interrupt handling routines.  All of the following
- * subroutines are declared as inline and are folded into
- * rs_interrupt().  They were separated out for readability's sake.
- *
- * Note: rs_interrupt() is a "fast" interrupt, which means that it
- * runs with interrupts turned off.  People who may want to modify
- * rs_interrupt() should try to keep the interrupt handler as fast as
- * possible.  After you are done making modifications, it is not a bad
- * idea to do:
- *
- * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
- *
- * and look at the resulting assemble code in serial.s.
- *
- *                             - Ted Ts'o (tytso@mit.edu), 7-Mar-93
- * -----------------------------------------------------------------------
- */
-
-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)
-{
-       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)
-{
-       struct tty_struct *tty = info->port.tty;
-       int i;
-       struct esp_pio_buffer *pio_buf;
-       struct esp_pio_buffer *err_buf;
-       unsigned char status_mask;
-
-       pio_buf = get_pio_buffer();
-
-       if (!pio_buf)
-               return;
-
-       err_buf = get_pio_buffer();
-
-       if (!err_buf) {
-               release_pio_buffer(pio_buf);
-               return;
-       }
-
-       status_mask = (info->read_status_mask >> 2) & 0x07;
-
-       for (i = 0; i < num_bytes - 1; i += 2) {
-               *((unsigned short *)(pio_buf->data + i)) =
-                       inw(info->io_port + UART_ESI_RX);
-               err_buf->data[i] = serial_in(info, UART_ESI_RWS);
-               err_buf->data[i + 1] = (err_buf->data[i] >> 3) & status_mask;
-               err_buf->data[i] &= status_mask;
-       }
-
-       if (num_bytes & 0x0001) {
-               pio_buf->data[num_bytes - 1] = serial_in(info, UART_ESI_RX);
-               err_buf->data[num_bytes - 1] =
-                       (serial_in(info, UART_ESI_RWS) >> 3) & status_mask;
-       }
-
-       /* make sure everything is still ok since interrupts were enabled */
-       tty = info->port.tty;
-
-       if (!tty) {
-               release_pio_buffer(pio_buf);
-               release_pio_buffer(err_buf);
-               info->stat_flags &= ~ESP_STAT_RX_TIMEOUT;
-               return;
-       }
-
-       status_mask = (info->ignore_status_mask >> 2) & 0x07;
-
-       for (i = 0; i < num_bytes; i++) {
-               if (!(err_buf->data[i] & status_mask)) {
-                       int flag = 0;
-
-                       if (err_buf->data[i] & 0x04) {
-                               flag = TTY_BREAK;
-                               if (info->port.flags & ASYNC_SAK)
-                                       do_SAK(tty);
-                       } else if (err_buf->data[i] & 0x02)
-                               flag = TTY_FRAME;
-                       else if (err_buf->data[i] & 0x01)
-                               flag = TTY_PARITY;
-                       tty_insert_flip_char(tty, pio_buf->data[i], flag);
-               }
-       }
-
-       tty_schedule_flip(tty);
-
-       info->stat_flags &= ~ESP_STAT_RX_TIMEOUT;
-       release_pio_buffer(pio_buf);
-       release_pio_buffer(err_buf);
-}
-
-static void program_isa_dma(int dma, int dir, unsigned long addr, int len)
-{
-       unsigned long flags;
-
-       flags = claim_dma_lock();
-       disable_dma(dma);
-       clear_dma_ff(dma);
-       set_dma_mode(dma, dir);
-       set_dma_addr(dma, addr);
-       set_dma_count(dma, len);
-       enable_dma(dma);
-       release_dma_lock(flags);
-}
-
-static void receive_chars_dma(struct esp_struct *info, int num_bytes)
-{
-       info->stat_flags &= ~ESP_STAT_RX_TIMEOUT;
-       dma_bytes = num_bytes;
-       info->stat_flags |= ESP_STAT_DMA_RX;
-
-       program_isa_dma(dma, DMA_MODE_READ, isa_virt_to_bus(dma_buffer),
-                                                               dma_bytes);
-       serial_out(info, UART_ESI_CMD1, ESI_START_DMA_RX);
-}
-
-static inline void receive_chars_dma_done(struct esp_struct *info,
-                                           int status)
-{
-       struct tty_struct *tty = info->port.tty;
-       int num_bytes;
-       unsigned long flags;
-
-       flags = claim_dma_lock();
-       disable_dma(dma);
-       clear_dma_ff(dma);
-
-       info->stat_flags &= ~ESP_STAT_DMA_RX;
-       num_bytes = dma_bytes - get_dma_residue(dma);
-       release_dma_lock(flags);
-
-       info->icount.rx += num_bytes;
-
-       if (num_bytes > 0) {
-               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 & 0x10) {
-                               statflag = TTY_BREAK;
-                               (info->icount.brk)++;
-                               if (info->port.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_schedule_flip(tty);
-       }
-
-       if (dma_bytes != num_bytes) {
-               num_bytes = dma_bytes - num_bytes;
-               dma_bytes = 0;
-               receive_chars_dma(info, num_bytes);
-       } else
-               dma_bytes = 0;
-}
-
-/* Caller must hold info->lock */
-
-static inline void transmit_chars_pio(struct esp_struct *info,
-                                       int space_avail)
-{
-       int i;
-       struct esp_pio_buffer *pio_buf;
-
-       pio_buf = get_pio_buffer();
-
-       if (!pio_buf)
-               return;
-
-       while (space_avail && info->xmit_cnt) {
-               if (info->xmit_tail + space_avail <= ESP_XMIT_SIZE) {
-                       memcpy(pio_buf->data,
-                              &(info->xmit_buf[info->xmit_tail]),
-                              space_avail);
-               } else {
-                       i = ESP_XMIT_SIZE - info->xmit_tail;
-                       memcpy(pio_buf->data,
-                              &(info->xmit_buf[info->xmit_tail]), i);
-                       memcpy(&(pio_buf->data[i]), info->xmit_buf,
-                              space_avail - i);
-               }
-
-               info->xmit_cnt -= space_avail;
-               info->xmit_tail = (info->xmit_tail + space_avail) &
-                       (ESP_XMIT_SIZE - 1);
-
-               for (i = 0; i < space_avail - 1; i += 2) {
-                       outw(*((unsigned short *)(pio_buf->data + i)),
-                            info->io_port + UART_ESI_TX);
-               }
-
-               if (space_avail & 0x0001)
-                       serial_out(info, UART_ESI_TX,
-                                  pio_buf->data[space_avail - 1]);
-
-               if (info->xmit_cnt) {
-                       serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND);
-                       serial_out(info, UART_ESI_CMD1, ESI_GET_TX_AVAIL);
-                       space_avail = serial_in(info, UART_ESI_STAT1) << 8;
-                       space_avail |= serial_in(info, UART_ESI_STAT2);
-
-                       if (space_avail > info->xmit_cnt)
-                               space_avail = info->xmit_cnt;
-               }
-       }
-
-       if (info->xmit_cnt < WAKEUP_CHARS) {
-               if (info->port.tty)
-                       tty_wakeup(info->port.tty);
-
-#ifdef SERIAL_DEBUG_INTR
-               printk("THRE...");
-#endif
-
-               if (info->xmit_cnt <= 0) {
-                       info->IER &= ~UART_IER_THRI;
-                       serial_out(info, UART_ESI_CMD1,
-                                  ESI_SET_SRV_MASK);
-                       serial_out(info, UART_ESI_CMD2, info->IER);
-               }
-       }
-
-       release_pio_buffer(pio_buf);
-}
-
-/* Caller must hold info->lock */
-static inline void transmit_chars_dma(struct esp_struct *info, int num_bytes)
-{
-       dma_bytes = num_bytes;
-
-       if (info->xmit_tail + dma_bytes <= ESP_XMIT_SIZE) {
-               memcpy(dma_buffer, &(info->xmit_buf[info->xmit_tail]),
-                      dma_bytes);
-       } else {
-               int i = ESP_XMIT_SIZE - info->xmit_tail;
-               memcpy(dma_buffer, &(info->xmit_buf[info->xmit_tail]),
-                       i);
-               memcpy(&(dma_buffer[i]), info->xmit_buf, dma_bytes - i);
-       }
-
-       info->xmit_cnt -= dma_bytes;
-       info->xmit_tail = (info->xmit_tail + dma_bytes) & (ESP_XMIT_SIZE - 1);
-
-       if (info->xmit_cnt < WAKEUP_CHARS) {
-               if (info->port.tty)
-                       tty_wakeup(info->port.tty);
-
-#ifdef SERIAL_DEBUG_INTR
-               printk("THRE...");
-#endif
-
-               if (info->xmit_cnt <= 0) {
-                       info->IER &= ~UART_IER_THRI;
-                       serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
-                       serial_out(info, UART_ESI_CMD2, info->IER);
-               }
-       }
-
-       info->stat_flags |= ESP_STAT_DMA_TX;
-
-       program_isa_dma(dma, DMA_MODE_WRITE, isa_virt_to_bus(dma_buffer),
-                                                               dma_bytes);
-       serial_out(info, UART_ESI_CMD1, ESI_START_DMA_TX);
-}
-
-static inline void transmit_chars_dma_done(struct esp_struct *info)
-{
-       int num_bytes;
-       unsigned long flags;
-
-       flags = claim_dma_lock();
-       disable_dma(dma);
-       clear_dma_ff(dma);
-
-       num_bytes = dma_bytes - get_dma_residue(dma);
-       info->icount.tx += dma_bytes;
-       release_dma_lock(flags);
-
-       if (dma_bytes != num_bytes) {
-               dma_bytes -= num_bytes;
-               memmove(dma_buffer, dma_buffer + num_bytes, dma_bytes);
-
-               program_isa_dma(dma, DMA_MODE_WRITE,
-                               isa_virt_to_bus(dma_buffer), dma_bytes);
-
-               serial_out(info, UART_ESI_CMD1, ESI_START_DMA_TX);
-       } else {
-               dma_bytes = 0;
-               info->stat_flags &= ~ESP_STAT_DMA_TX;
-       }
-}
-
-static void check_modem_status(struct esp_struct *info)
-{
-       int     status;
-
-       serial_out(info, UART_ESI_CMD1, ESI_GET_UART_STAT);
-       status = serial_in(info, UART_ESI_STAT2);
-
-       if (status & UART_MSR_ANY_DELTA) {
-               /* update input line counters */
-               if (status & UART_MSR_TERI)
-                       info->icount.rng++;
-               if (status & UART_MSR_DDSR)
-                       info->icount.dsr++;
-               if (status & UART_MSR_DDCD)
-                       info->icount.dcd++;
-               if (status & UART_MSR_DCTS)
-                       info->icount.cts++;
-               wake_up_interruptible(&info->port.delta_msr_wait);
-       }
-
-       if ((info->port.flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
-#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
-               printk("ttys%d CD now %s...", info->line,
-                      (status & UART_MSR_DCD) ? "on" : "off");
-#endif
-               if (status & UART_MSR_DCD)
-                       wake_up_interruptible(&info->port.open_wait);
-               else {
-#ifdef SERIAL_DEBUG_OPEN
-                       printk("scheduling hangup...");
-#endif
-                       tty_hangup(info->port.tty);
-               }
-       }
-}
-
-/*
- * This is the serial driver's interrupt routine
- */
-static irqreturn_t rs_interrupt_single(int irq, void *dev_id)
-{
-       struct esp_struct *info;
-       unsigned err_status;
-       unsigned int scratch;
-
-#ifdef SERIAL_DEBUG_INTR
-       printk("rs_interrupt_single(%d)...", irq);
-#endif
-       info = (struct esp_struct *)dev_id;
-       err_status = 0;
-       scratch = serial_in(info, UART_ESI_SID);
-
-       spin_lock(&info->lock);
-
-       if (!info->port.tty) {
-               spin_unlock(&info->lock);
-               return IRQ_NONE;
-       }
-
-       if (scratch & 0x04) { /* error */
-               serial_out(info, UART_ESI_CMD1, ESI_GET_ERR_STAT);
-               err_status = serial_in(info, UART_ESI_STAT1);
-               serial_in(info, UART_ESI_STAT2);
-
-               if (err_status & 0x01)
-                       info->stat_flags |= ESP_STAT_RX_TIMEOUT;
-
-               if (err_status & 0x20) /* UART status */
-                       check_modem_status(info);
-
-               if (err_status & 0x80) /* Start break */
-                       wake_up_interruptible(&info->break_wait);
-       }
-
-       if ((scratch & 0x88) || /* DMA completed or timed out */
-           (err_status & 0x1c) /* receive error */) {
-               if (info->stat_flags & ESP_STAT_DMA_RX)
-                       receive_chars_dma_done(info, err_status);
-               else if (info->stat_flags & ESP_STAT_DMA_TX)
-                       transmit_chars_dma_done(info);
-       }
-
-       if (!(info->stat_flags & (ESP_STAT_DMA_RX | ESP_STAT_DMA_TX)) &&
-           ((scratch & 0x01) || (info->stat_flags & ESP_STAT_RX_TIMEOUT)) &&
-           (info->IER & UART_IER_RDI)) {
-               int num_bytes;
-
-               serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND);
-               serial_out(info, UART_ESI_CMD1, ESI_GET_RX_AVAIL);
-               num_bytes = serial_in(info, UART_ESI_STAT1) << 8;
-               num_bytes |= serial_in(info, UART_ESI_STAT2);
-
-               num_bytes = tty_buffer_request_room(info->port.tty, num_bytes);
-
-               if (num_bytes) {
-                       if (dma_bytes ||
-                           (info->stat_flags & ESP_STAT_USE_PIO) ||
-                           (num_bytes <= info->config.pio_threshold))
-                               receive_chars_pio(info, num_bytes);
-                       else
-                               receive_chars_dma(info, num_bytes);
-               }
-       }
-
-       if (!(info->stat_flags & (ESP_STAT_DMA_RX | ESP_STAT_DMA_TX)) &&
-           (scratch & 0x02) && (info->IER & UART_IER_THRI)) {
-               if ((info->xmit_cnt <= 0) || info->port.tty->stopped) {
-                       info->IER &= ~UART_IER_THRI;
-                       serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
-                       serial_out(info, UART_ESI_CMD2, info->IER);
-               } else {
-                       int num_bytes;
-
-                       serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND);
-                       serial_out(info, UART_ESI_CMD1, ESI_GET_TX_AVAIL);
-                       num_bytes = serial_in(info, UART_ESI_STAT1) << 8;
-                       num_bytes |= serial_in(info, UART_ESI_STAT2);
-
-                       if (num_bytes > info->xmit_cnt)
-                               num_bytes = info->xmit_cnt;
-
-                       if (num_bytes) {
-                               if (dma_bytes ||
-                                   (info->stat_flags & ESP_STAT_USE_PIO) ||
-                                   (num_bytes <= info->config.pio_threshold))
-                                       transmit_chars_pio(info, num_bytes);
-                               else
-                                       transmit_chars_dma(info, num_bytes);
-                       }
-               }
-       }
-
-       info->last_active = jiffies;
-
-#ifdef SERIAL_DEBUG_INTR
-       printk("end.\n");
-#endif
-       spin_unlock(&info->lock);
-       return IRQ_HANDLED;
-}
-
-/*
- * -------------------------------------------------------------------
- * Here ends the serial interrupt routines.
- * -------------------------------------------------------------------
- */
-
-/*
- * ---------------------------------------------------------------
- * Low level utility subroutines for the serial driver:  routines to
- * 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 void esp_basic_init(struct esp_struct *info)
-{
-       /* put ESPC in enhanced mode */
-       serial_out(info, UART_ESI_CMD1, ESI_SET_MODE);
-
-       if (info->stat_flags & ESP_STAT_NEVER_DMA)
-               serial_out(info, UART_ESI_CMD2, 0x01);
-       else
-               serial_out(info, UART_ESI_CMD2, 0x31);
-
-       /* disable interrupts for now */
-       serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
-       serial_out(info, UART_ESI_CMD2, 0x00);
-
-       /* set interrupt and DMA channel */
-       serial_out(info, UART_ESI_CMD1, ESI_SET_IRQ);
-
-       if (info->stat_flags & ESP_STAT_NEVER_DMA)
-               serial_out(info, UART_ESI_CMD2, 0x01);
-       else
-               serial_out(info, UART_ESI_CMD2, (dma << 4) | 0x01);
-
-       serial_out(info, UART_ESI_CMD1, ESI_SET_ENH_IRQ);
-
-       if (info->line % 8)     /* secondary port */
-               serial_out(info, UART_ESI_CMD2, 0x0d);  /* shared */
-       else if (info->irq == 9)
-               serial_out(info, UART_ESI_CMD2, 0x02);
-       else
-               serial_out(info, UART_ESI_CMD2, info->irq);
-
-       /* set error status mask (check this) */
-       serial_out(info, UART_ESI_CMD1, ESI_SET_ERR_MASK);
-
-       if (info->stat_flags & ESP_STAT_NEVER_DMA)
-               serial_out(info, UART_ESI_CMD2, 0xa1);
-       else
-               serial_out(info, UART_ESI_CMD2, 0xbd);
-
-       serial_out(info, UART_ESI_CMD2, 0x00);
-
-       /* set DMA timeout */
-       serial_out(info, UART_ESI_CMD1, ESI_SET_DMA_TMOUT);
-       serial_out(info, UART_ESI_CMD2, 0xff);
-
-       /* set FIFO trigger levels */
-       serial_out(info, UART_ESI_CMD1, ESI_SET_TRIGGER);
-       serial_out(info, UART_ESI_CMD2, info->config.rx_trigger >> 8);
-       serial_out(info, UART_ESI_CMD2, info->config.rx_trigger);
-       serial_out(info, UART_ESI_CMD2, info->config.tx_trigger >> 8);
-       serial_out(info, UART_ESI_CMD2, info->config.tx_trigger);
-
-       /* Set clock scaling and wait states */
-       serial_out(info, UART_ESI_CMD1, ESI_SET_PRESCALAR);
-       serial_out(info, UART_ESI_CMD2, 0x04 | ESPC_SCALE);
-
-       /* set reinterrupt pacing */
-       serial_out(info, UART_ESI_CMD1, ESI_SET_REINTR);
-       serial_out(info, UART_ESI_CMD2, 0xff);
-}
-
-static int startup(struct esp_struct *info)
-{
-       unsigned long flags;
-       int     retval = 0;
-       unsigned int num_chars;
-
-       spin_lock_irqsave(&info->lock, flags);
-
-       if (info->port.flags & ASYNC_INITIALIZED)
-               goto out;
-
-       if (!info->xmit_buf) {
-               info->xmit_buf = (unsigned char *)get_zeroed_page(GFP_ATOMIC);
-               retval = -ENOMEM;
-               if (!info->xmit_buf)
-                       goto out;
-       }
-
-#ifdef SERIAL_DEBUG_OPEN
-       printk(KERN_DEBUG "starting up ttys%d (irq %d)...",
-                                               info->line, info->irq);
-#endif
-
-       /* Flush the RX buffer.  Using the ESI flush command may cause */
-       /* wild interrupts, so read all the data instead. */
-
-       serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND);
-       serial_out(info, UART_ESI_CMD1, ESI_GET_RX_AVAIL);
-       num_chars = serial_in(info, UART_ESI_STAT1) << 8;
-       num_chars |= serial_in(info, UART_ESI_STAT2);
-
-       while (num_chars > 1) {
-               inw(info->io_port + UART_ESI_RX);
-               num_chars -= 2;
-       }
-
-       if (num_chars)
-               serial_in(info, UART_ESI_RX);
-
-       /* set receive character timeout */
-       serial_out(info, UART_ESI_CMD1, ESI_SET_RX_TIMEOUT);
-       serial_out(info, UART_ESI_CMD2, info->config.rx_timeout);
-
-       /* clear all flags except the "never DMA" flag */
-       info->stat_flags &= ESP_STAT_NEVER_DMA;
-
-       if (info->stat_flags & ESP_STAT_NEVER_DMA)
-               info->stat_flags |= ESP_STAT_USE_PIO;
-
-       spin_unlock_irqrestore(&info->lock, flags);
-
-       /*
-        * Allocate the IRQ
-        */
-
-       retval = request_irq(info->irq, rs_interrupt_single, IRQF_SHARED,
-                            "esp serial", info);
-
-       if (retval) {
-               if (capable(CAP_SYS_ADMIN)) {
-                       if (info->port.tty)
-                               set_bit(TTY_IO_ERROR,
-                                       &info->port.tty->flags);
-                       retval = 0;
-               }
-               goto out_unlocked;
-       }
-
-       if (!(info->stat_flags & ESP_STAT_USE_PIO) && !dma_buffer) {
-               dma_buffer = (char *)__get_dma_pages(
-                       GFP_KERNEL, get_order(DMA_BUFFER_SZ));
-
-               /* use PIO mode if DMA buf/chan cannot be allocated */
-               if (!dma_buffer)
-                       info->stat_flags |= ESP_STAT_USE_PIO;
-               else if (request_dma(dma, "esp serial")) {
-                       free_pages((unsigned long)dma_buffer,
-                                  get_order(DMA_BUFFER_SZ));
-                       dma_buffer = NULL;
-                       info->stat_flags |= ESP_STAT_USE_PIO;
-               }
-
-       }
-
-       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);
-
-       /*
-        * Finally, enable interrupts
-        */
-       /* info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI; */
-       info->IER = UART_IER_RLSI | UART_IER_RDI | UART_IER_DMA_TMOUT |
-                       UART_IER_DMA_TC;
-       serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
-       serial_out(info, UART_ESI_CMD2, info->IER);
-
-       if (info->port.tty)
-               clear_bit(TTY_IO_ERROR, &info->port.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
-        */
-       if (info->port.tty) {
-               if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
-                       info->port.tty->alt_speed = 57600;
-               if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
-                       info->port.tty->alt_speed = 115200;
-               if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
-                       info->port.tty->alt_speed = 230400;
-               if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
-                       info->port.tty->alt_speed = 460800;
-       }
-
-       /*
-        * set the speed of the serial port
-        */
-       change_speed(info);
-       info->port.flags |= ASYNC_INITIALIZED;
-       return 0;
-
-out:
-       spin_unlock_irqrestore(&info->lock, flags);
-out_unlocked:
-       return retval;
-}
-
-/*
- * 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 esp_struct *info)
-{
-       unsigned long   flags, f;
-
-       if (!(info->port.flags & ASYNC_INITIALIZED))
-               return;
-
-#ifdef SERIAL_DEBUG_OPEN
-       printk("Shutting down serial port %d (irq %d)....", info->line,
-              info->irq);
-#endif
-
-       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
-        */
-       wake_up_interruptible(&info->port.delta_msr_wait);
-       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);
-               clear_dma_ff(dma);
-               release_dma_lock(f);
-
-               dma_bytes = 0;
-       }
-
-       /*
-        * Free the IRQ
-        */
-       free_irq(info->irq, info);
-
-       if (dma_buffer) {
-               struct esp_struct *current_port = ports;
-
-               while (current_port) {
-                       if ((current_port != info) &&
-                           (current_port->port.flags & ASYNC_INITIALIZED))
-                               break;
-
-                       current_port = current_port->next_port;
-               }
-
-               if (!current_port) {
-                       free_dma(dma);
-                       free_pages((unsigned long)dma_buffer,
-                                  get_order(DMA_BUFFER_SZ));
-                       dma_buffer = NULL;
-               }
-       }
-
-       if (info->xmit_buf) {
-               free_page((unsigned long) info->xmit_buf);
-               info->xmit_buf = NULL;
-       }
-
-       info->IER = 0;
-       serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
-       serial_out(info, UART_ESI_CMD2, 0x00);
-
-       if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL))
-               info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
-
-       info->MCR &= ~UART_MCR_OUT2;
-       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);
-
-       if (info->port.tty)
-               set_bit(TTY_IO_ERROR, &info->port.tty->flags);
-
-       info->port.flags &= ~ASYNC_INITIALIZED;
-       spin_unlock_irqrestore(&info->lock, flags);
-}
-
-/*
- * 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 esp_struct *info)
-{
-       unsigned short port;
-       int     quot = 0;
-       unsigned cflag, cval;
-       int     baud, bits;
-       unsigned char flow1 = 0, flow2 = 0;
-       unsigned long flags;
-
-       if (!info->port.tty || !info->port.tty->termios)
-               return;
-       cflag = info->port.tty->termios->c_cflag;
-       port = info->io_port;
-
-       /* byte size and parity */
-       switch (cflag & CSIZE) {
-       case CS5: cval = 0x00; bits = 7; break;
-       case CS6: cval = 0x01; bits = 8; break;
-       case CS7: cval = 0x02; bits = 9; break;
-       case CS8: cval = 0x03; bits = 10; break;
-       default:  cval = 0x00; bits = 7; break;
-       }
-       if (cflag & CSTOPB) {
-               cval |= 0x04;
-               bits++;
-       }
-       if (cflag & PARENB) {
-               cval |= UART_LCR_PARITY;
-               bits++;
-       }
-       if (!(cflag & PARODD))
-               cval |= UART_LCR_EPAR;
-#ifdef CMSPAR
-       if (cflag & CMSPAR)
-               cval |= UART_LCR_SPAR;
-#endif
-       baud = tty_get_baud_rate(info->port.tty);
-       if (baud == 38400 &&
-               ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))
-               quot = info->custom_divisor;
-       else {
-               if (baud == 134) /* Special case since 134 is really 134.5 */
-                       quot = (2*BASE_BAUD / 269);
-               else if (baud)
-                       quot = BASE_BAUD / baud;
-       }
-       /* If the quotient is ever zero, default to 9600 bps */
-       if (!quot)
-               quot = BASE_BAUD / 9600;
-
-       if (baud) {
-               /* Actual rate */
-               baud = BASE_BAUD/quot;
-               tty_encode_baud_rate(info->port.tty, baud, baud);
-       }
-       info->timeout = ((1024 * HZ * bits * quot) / BASE_BAUD) + (HZ / 50);
-
-       /* CTS flow control flag and modem status interrupts */
-       /* info->IER &= ~UART_IER_MSI; */
-       if (cflag & CRTSCTS) {
-               info->port.flags |= ASYNC_CTS_FLOW;
-               /* info->IER |= UART_IER_MSI; */
-               flow1 = 0x04;
-               flow2 = 0x10;
-       } else
-               info->port.flags &= ~ASYNC_CTS_FLOW;
-       if (cflag & CLOCAL)
-               info->port.flags &= ~ASYNC_CHECK_CD;
-       else
-               info->port.flags |= ASYNC_CHECK_CD;
-
-       /*
-        * Set up parity check flag
-        */
-       info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
-       if (I_INPCK(info->port.tty))
-               info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
-       if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty))
-               info->read_status_mask |= UART_LSR_BI;
-
-       info->ignore_status_mask = 0;
-#if 0
-       /* This should be safe, but for some broken bits of hardware... */
-       if (I_IGNPAR(info->port.tty)) {
-               info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
-               info->read_status_mask |= UART_LSR_PE | UART_LSR_FE;
-       }
-#endif
-       if (I_IGNBRK(info->port.tty)) {
-               info->ignore_status_mask |= UART_LSR_BI;
-               info->read_status_mask |= UART_LSR_BI;
-               /*
-                * If we're ignore parity and break indicators, ignore
-                * overruns too.  (For real raw support).
-                */
-               if (I_IGNPAR(info->port.tty)) {
-                       info->ignore_status_mask |= UART_LSR_OE | \
-                               UART_LSR_PE | UART_LSR_FE;
-                       info->read_status_mask |= UART_LSR_OE | \
-                               UART_LSR_PE | UART_LSR_FE;
-               }
-       }
-
-       if (I_IXOFF(info->port.tty))
-               flow1 |= 0x81;
-
-       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);
-       serial_out(info, UART_ESI_CMD2, quot & 0xff);
-
-       /* set data bits, parity, etc. */
-       serial_out(info, UART_ESI_CMD1, ESI_WRITE_UART);
-       serial_out(info, UART_ESI_CMD2, UART_LCR);
-       serial_out(info, UART_ESI_CMD2, cval);
-
-       /* Enable flow control */
-       serial_out(info, UART_ESI_CMD1, ESI_SET_FLOW_CNTL);
-       serial_out(info, UART_ESI_CMD2, flow1);
-       serial_out(info, UART_ESI_CMD2, flow2);
-
-       /* set flow control characters (XON/XOFF only) */
-       if (I_IXOFF(info->port.tty)) {
-               serial_out(info, UART_ESI_CMD1, ESI_SET_FLOW_CHARS);
-               serial_out(info, UART_ESI_CMD2, START_CHAR(info->port.tty));
-               serial_out(info, UART_ESI_CMD2, STOP_CHAR(info->port.tty));
-               serial_out(info, UART_ESI_CMD2, 0x10);
-               serial_out(info, UART_ESI_CMD2, 0x21);
-               switch (cflag & CSIZE) {
-               case CS5:
-                       serial_out(info, UART_ESI_CMD2, 0x1f);
-                       break;
-               case CS6:
-                       serial_out(info, UART_ESI_CMD2, 0x3f);
-                       break;
-               case CS7:
-               case CS8:
-                       serial_out(info, UART_ESI_CMD2, 0x7f);
-                       break;
-               default:
-                       serial_out(info, UART_ESI_CMD2, 0xff);
-                       break;
-               }
-       }
-
-       /* Set high/low water */
-       serial_out(info, UART_ESI_CMD1, ESI_SET_FLOW_LVL);
-       serial_out(info, UART_ESI_CMD2, info->config.flow_off >> 8);
-       serial_out(info, UART_ESI_CMD2, info->config.flow_off);
-       serial_out(info, UART_ESI_CMD2, info->config.flow_on >> 8);
-       serial_out(info, UART_ESI_CMD2, info->config.flow_on);
-
-       spin_unlock_irqrestore(&info->lock, flags);
-}
-
-static int rs_put_char(struct tty_struct *tty, unsigned char ch)
-{
-       struct esp_struct *info = tty->driver_data;
-       unsigned long flags;
-       int ret = 0;
-
-       if (serial_paranoia_check(info, tty->name, "rs_put_char"))
-               return 0;
-
-       if (!info->xmit_buf)
-               return 0;
-
-       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++;
-               ret = 1;
-       }
-       spin_unlock_irqrestore(&info->lock, flags);
-       return ret;
-}
-
-static void rs_flush_chars(struct tty_struct *tty)
-{
-       struct esp_struct *info = tty->driver_data;
-       unsigned long flags;
-
-       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)
-               goto out;
-
-       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);
-       }
-out:
-       spin_unlock_irqrestore(&info->lock, flags);
-}
-
-static int rs_write(struct tty_struct *tty,
-                   const unsigned char *buf, int count)
-{
-       int     c, t, ret = 0;
-       struct esp_struct *info = tty->driver_data;
-       unsigned long flags;
-
-       if (serial_paranoia_check(info, tty->name, "rs_write"))
-               return 0;
-
-       if (!info->xmit_buf)
-               return 0;
-
-       while (1) {
-               /* Thanks to R. Wolff for suggesting how to do this with */
-               /* interrupts enabled */
-
-               c = count;
-               t = ESP_XMIT_SIZE - info->xmit_cnt - 1;
-
-               if (t < c)
-                       c = t;
-
-               t = ESP_XMIT_SIZE - info->xmit_head;
-
-               if (t < c)
-                       c = t;
-
-               if (c <= 0)
-                       break;
-
-               memcpy(info->xmit_buf + info->xmit_head, buf, c);
-
-               info->xmit_head = (info->xmit_head + c) & (ESP_XMIT_SIZE-1);
-               info->xmit_cnt += c;
-               buf += c;
-               count -= c;
-               ret += c;
-       }
-
-       spin_lock_irqsave(&info->lock, flags);
-
-       if (info->xmit_cnt && !tty->stopped && !(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);
-       }
-
-       spin_unlock_irqrestore(&info->lock, flags);
-       return ret;
-}
-
-static int rs_write_room(struct tty_struct *tty)
-{
-       struct esp_struct *info = 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;
-}
-
-static int rs_chars_in_buffer(struct tty_struct *tty)
-{
-       struct esp_struct *info = tty->driver_data;
-
-       if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer"))
-               return 0;
-       return info->xmit_cnt;
-}
-
-static void rs_flush_buffer(struct tty_struct *tty)
-{
-       struct esp_struct *info = tty->driver_data;
-       unsigned long flags;
-
-       if (serial_paranoia_check(info, tty->name, "rs_flush_buffer"))
-               return;
-       spin_lock_irqsave(&info->lock, flags);
-       info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-       spin_unlock_irqrestore(&info->lock, flags);
-       tty_wakeup(tty);
-}
-
-/*
- * ------------------------------------------------------------
- * rs_throttle()
- *
- * This routine is called by the upper-layer tty layer to signal that
- * incoming characters should be throttled.
- * ------------------------------------------------------------
- */
-static void rs_throttle(struct tty_struct *tty)
-{
-       struct esp_struct *info = tty->driver_data;
-       unsigned long flags;
-#ifdef SERIAL_DEBUG_THROTTLE
-       char    buf[64];
-
-       printk("throttle %s: %d....\n", tty_name(tty, buf),
-                                               tty_chars_in_buffer(tty));
-#endif
-
-       if (serial_paranoia_check(info, tty->name, "rs_throttle"))
-               return;
-
-       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);
-       spin_unlock_irqrestore(&info->lock, flags);
-}
-
-static void rs_unthrottle(struct tty_struct *tty)
-{
-       struct esp_struct *info = tty->driver_data;
-       unsigned long flags;
-#ifdef SERIAL_DEBUG_THROTTLE
-       char    buf[64];
-
-       printk(KERN_DEBUG "unthrottle %s: %d....\n", tty_name(tty, buf),
-              tty_chars_in_buffer(tty));
-#endif
-
-       if (serial_paranoia_check(info, tty->name, "rs_unthrottle"))
-               return;
-
-       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);
-       spin_unlock_irqrestore(&info->lock, flags);
-}
-
-/*
- * ------------------------------------------------------------
- * rs_ioctl() and friends
- * ------------------------------------------------------------
- */
-
-static int get_serial_info(struct esp_struct *info,
-                          struct serial_struct __user *retinfo)
-{
-       struct serial_struct tmp;
-
-       lock_kernel();
-       memset(&tmp, 0, sizeof(tmp));
-       tmp.type = PORT_16550A;
-       tmp.line = info->line;
-       tmp.port = info->io_port;
-       tmp.irq = info->irq;
-       tmp.flags = info->port.flags;
-       tmp.xmit_fifo_size = 1024;
-       tmp.baud_base = BASE_BAUD;
-       tmp.close_delay = info->close_delay;
-       tmp.closing_wait = info->closing_wait;
-       tmp.custom_divisor = info->custom_divisor;
-       tmp.hub6 = 0;
-       unlock_kernel();
-       if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
-               return -EFAULT;
-       return 0;
-}
-
-static int get_esp_config(struct esp_struct *info,
-                         struct hayes_esp_config __user *retinfo)
-{
-       struct hayes_esp_config tmp;
-
-       if (!retinfo)
-               return -EFAULT;
-
-       memset(&tmp, 0, sizeof(tmp));
-       lock_kernel();
-       tmp.rx_timeout = info->config.rx_timeout;
-       tmp.rx_trigger = info->config.rx_trigger;
-       tmp.tx_trigger = info->config.tx_trigger;
-       tmp.flow_off = info->config.flow_off;
-       tmp.flow_on = info->config.flow_on;
-       tmp.pio_threshold = info->config.pio_threshold;
-       tmp.dma_channel = (info->stat_flags & ESP_STAT_NEVER_DMA ? 0 : dma);
-       unlock_kernel();
-
-       return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
-}
-
-static int set_serial_info(struct esp_struct *info,
-                          struct serial_struct __user *new_info)
-{
-       struct serial_struct new_serial;
-       struct esp_struct old_info;
-       unsigned int change_irq;
-       int retval = 0;
-       struct esp_struct *current_async;
-
-       if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
-               return -EFAULT;
-       old_info = *info;
-
-       if ((new_serial.type != PORT_16550A) ||
-           (new_serial.hub6) ||
-           (info->io_port != new_serial.port) ||
-           (new_serial.baud_base != BASE_BAUD) ||
-           (new_serial.irq > 15) ||
-           (new_serial.irq < 2) ||
-           (new_serial.irq == 6) ||
-           (new_serial.irq == 8) ||
-           (new_serial.irq == 13))
-               return -EINVAL;
-
-       change_irq = new_serial.irq != info->irq;
-
-       if (change_irq && (info->line % 8))
-               return -EINVAL;
-
-       if (!capable(CAP_SYS_ADMIN)) {
-               if (change_irq ||
-                   (new_serial.close_delay != info->close_delay) ||
-                   ((new_serial.flags & ~ASYNC_USR_MASK) !=
-                    (info->port.flags & ~ASYNC_USR_MASK)))
-                       return -EPERM;
-               info->port.flags = ((info->port.flags & ~ASYNC_USR_MASK) |
-                              (new_serial.flags & ASYNC_USR_MASK));
-               info->custom_divisor = new_serial.custom_divisor;
-       } else {
-               if (new_serial.irq == 2)
-                       new_serial.irq = 9;
-
-               if (change_irq) {
-                       current_async = ports;
-
-                       while (current_async) {
-                               if ((current_async->line >= info->line) &&
-                                   (current_async->line < (info->line + 8))) {
-                                       if (current_async == info) {
-                                               if (current_async->port.count > 1)
-                                                       return -EBUSY;
-                                       } else if (current_async->port.count)
-                                               return -EBUSY;
-                               }
-
-                               current_async = current_async->next_port;
-                       }
-               }
-
-               /*
-                * OK, past this point, all the error checking has been done.
-                * At this point, we start making changes.....
-                */
-
-               info->port.flags = ((info->port.flags & ~ASYNC_FLAGS) |
-                              (new_serial.flags & ASYNC_FLAGS));
-               info->custom_divisor = new_serial.custom_divisor;
-               info->close_delay = new_serial.close_delay * HZ/100;
-               info->closing_wait = new_serial.closing_wait * HZ/100;
-
-               if (change_irq) {
-                       /*
-                        * We need to shutdown the serial port at the old
-                        * port/irq combination.
-                        */
-                       shutdown(info);
-
-                       current_async = ports;
-
-                       while (current_async) {
-                               if ((current_async->line >= info->line) &&
-                                   (current_async->line < (info->line + 8)))
-                                       current_async->irq = new_serial.irq;
-
-                               current_async = current_async->next_port;
-                       }
-
-                       serial_out(info, UART_ESI_CMD1, ESI_SET_ENH_IRQ);
-                       if (info->irq == 9)
-                               serial_out(info, UART_ESI_CMD2, 0x02);
-                       else
-                               serial_out(info, UART_ESI_CMD2, info->irq);
-               }
-       }
-
-       if (info->port.flags & ASYNC_INITIALIZED) {
-               if (((old_info.port.flags & ASYNC_SPD_MASK) !=
-                    (info->port.flags & ASYNC_SPD_MASK)) ||
-                   (old_info.custom_divisor != info->custom_divisor)) {
-                       if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
-                               info->port.tty->alt_speed = 57600;
-                       if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
-                               info->port.tty->alt_speed = 115200;
-                       if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
-                               info->port.tty->alt_speed = 230400;
-                       if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
-                               info->port.tty->alt_speed = 460800;
-                       change_speed(info);
-               }
-       } else
-               retval = startup(info);
-
-       return retval;
-}
-
-static int set_esp_config(struct esp_struct *info,
-                         struct hayes_esp_config __user *new_info)
-{
-       struct hayes_esp_config new_config;
-       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. */
-
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-
-       if (copy_from_user(&new_config, new_info, sizeof(new_config)))
-               return -EFAULT;
-
-       if ((new_config.flow_on >= new_config.flow_off) ||
-           (new_config.rx_trigger < 1) ||
-           (new_config.tx_trigger < 1) ||
-           (new_config.flow_off < 1) ||
-           (new_config.flow_on < 1) ||
-           (new_config.rx_trigger > 1023) ||
-           (new_config.tx_trigger > 1023) ||
-           (new_config.flow_off > 1023) ||
-           (new_config.flow_on > 1023) ||
-           (new_config.pio_threshold < 0) ||
-           (new_config.pio_threshold > 1024))
-               return -EINVAL;
-
-       if ((new_config.dma_channel != 1) && (new_config.dma_channel != 3))
-               new_config.dma_channel = 0;
-
-       if (info->stat_flags & ESP_STAT_NEVER_DMA)
-               change_dma = new_config.dma_channel;
-       else
-               change_dma = (new_config.dma_channel != dma);
-
-       if (change_dma) {
-               if (new_config.dma_channel) {
-                       /* PIO mode to DMA mode transition OR */
-                       /* change current DMA channel */
-                       current_async = ports;
-
-                       while (current_async) {
-                               if (current_async == info) {
-                                       if (current_async->port.count > 1)
-                                               return -EBUSY;
-                               } else if (current_async->port.count)
-                                       return -EBUSY;
-
-                               current_async = current_async->next_port;
-                       }
-
-                       shutdown(info);
-                       dma = new_config.dma_channel;
-                       info->stat_flags &= ~ESP_STAT_NEVER_DMA;
-
-                       /* 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 */
-                       if (info->port.count > 1)
-                               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);
-               }
-       }
-
-       info->config.pio_threshold = new_config.pio_threshold;
-
-       if ((new_config.flow_off != info->config.flow_off) ||
-           (new_config.flow_on != info->config.flow_on)) {
-               info->config.flow_off = new_config.flow_off;
-               info->config.flow_on = new_config.flow_on;
-
-               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);
-               spin_unlock_irqrestore(&info->lock, flags);
-       }
-
-       if ((new_config.rx_trigger != info->config.rx_trigger) ||
-           (new_config.tx_trigger != info->config.tx_trigger)) {
-               info->config.rx_trigger = new_config.rx_trigger;
-               info->config.tx_trigger = new_config.tx_trigger;
-               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);
-               serial_out(info, UART_ESI_CMD2, new_config.rx_trigger);
-               serial_out(info, UART_ESI_CMD2,
-                          new_config.tx_trigger >> 8);
-               serial_out(info, UART_ESI_CMD2, new_config.tx_trigger);
-               spin_unlock_irqrestore(&info->lock, flags);
-       }
-
-       if (new_config.rx_timeout != info->config.rx_timeout) {
-               info->config.rx_timeout = new_config.rx_timeout;
-               spin_lock_irqsave(&info->lock, flags);
-
-               if (info->IER & UART_IER_RDI) {
-                       serial_out(info, UART_ESI_CMD1,
-                                  ESI_SET_RX_TIMEOUT);
-                       serial_out(info, UART_ESI_CMD2,
-                                  new_config.rx_timeout);
-               }
-
-               spin_unlock_irqrestore(&info->lock, flags);
-       }
-
-       if (!(info->port.flags & ASYNC_INITIALIZED))
-               retval = startup(info);
-
-       return retval;
-}
-
-/*
- * get_lsr_info - get line status register info
- *
- * Purpose: Let user call ioctl() to get info when the UART physically
- *         is emptied.  On bus types like RS485, the transmitter must
- *         release the bus after transmitting. This must be done when
- *         the transmit shift register is empty, not be done when the
- *         transmit holding register is empty.  This functionality
- *         allows an RS485 driver to be written in user space.
- */
-static int get_lsr_info(struct esp_struct *info, unsigned int __user *value)
-{
-       unsigned char status;
-       unsigned int result;
-       unsigned long flags;
-
-       spin_lock_irqsave(&info->lock, flags);
-       serial_out(info, UART_ESI_CMD1, ESI_GET_UART_STAT);
-       status = serial_in(info, UART_ESI_STAT1);
-       spin_unlock_irqrestore(&info->lock, flags);
-       result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
-       return put_user(result, value);
-}
-
-
-static int esp_tiocmget(struct tty_struct *tty, struct file *file)
-{
-       struct esp_struct *info = tty->driver_data;
-       unsigned char control, status;
-       unsigned long flags;
-
-       if (serial_paranoia_check(info, tty->name, __func__))
-               return -ENODEV;
-       if (tty->flags & (1 << TTY_IO_ERROR))
-               return -EIO;
-
-       control = info->MCR;
-
-       spin_lock_irqsave(&info->lock, flags);
-       serial_out(info, UART_ESI_CMD1, ESI_GET_UART_STAT);
-       status = serial_in(info, UART_ESI_STAT2);
-       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)
-               | ((status  & UART_MSR_RI) ? TIOCM_RNG : 0)
-               | ((status  & UART_MSR_DSR) ? TIOCM_DSR : 0)
-               | ((status  & UART_MSR_CTS) ? TIOCM_CTS : 0);
-}
-
-static int esp_tiocmset(struct tty_struct *tty, struct file *file,
-                       unsigned int set, unsigned int clear)
-{
-       struct esp_struct *info = tty->driver_data;
-       unsigned long flags;
-
-       if (serial_paranoia_check(info, tty->name, __func__))
-               return -ENODEV;
-       if (tty->flags & (1 << TTY_IO_ERROR))
-               return -EIO;
-
-       spin_lock_irqsave(&info->lock, flags);
-
-       if (set & TIOCM_RTS)
-               info->MCR |= UART_MCR_RTS;
-       if (set & TIOCM_DTR)
-               info->MCR |= UART_MCR_DTR;
-
-       if (clear & TIOCM_RTS)
-               info->MCR &= ~UART_MCR_RTS;
-       if (clear & TIOCM_DTR)
-               info->MCR &= ~UART_MCR_DTR;
-
-       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);
-
-       spin_unlock_irqrestore(&info->lock, flags);
-       return 0;
-}
-
-/*
- * rs_break() --- routine which turns the break handling on or off
- */
-static int esp_break(struct tty_struct *tty, int break_state)
-{
-       struct esp_struct *info = tty->driver_data;
-       unsigned long flags;
-
-       if (serial_paranoia_check(info, tty->name, "esp_break"))
-               return -EINVAL;
-
-       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);
-       }
-       return 0;
-}
-
-static int rs_ioctl(struct tty_struct *tty, struct file *file,
-                   unsigned int cmd, unsigned long arg)
-{
-       struct esp_struct *info = tty->driver_data;
-       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;
-       int ret;
-
-       if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
-               return -ENODEV;
-
-       if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
-           (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD)  &&
-           (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT) &&
-           (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT) &&
-           (cmd != TIOCGHAYESESP) && (cmd != TIOCSHAYESESP)) {
-               if (tty->flags & (1 << TTY_IO_ERROR))
-                   return -EIO;
-       }
-
-       switch (cmd) {
-       case TIOCGSERIAL:
-               return get_serial_info(info, argp);
-       case TIOCSSERIAL:
-               lock_kernel();
-               ret = set_serial_info(info, argp);
-               unlock_kernel();
-               return ret;
-       case TIOCSERGWILD:
-               return put_user(0L, (unsigned long __user *)argp);
-       case TIOCSERGETLSR: /* Get line status register */
-               return get_lsr_info(info, argp);
-       case TIOCSERSWILD:
-               if (!capable(CAP_SYS_ADMIN))
-                       return -EPERM;
-               return 0;
-       /*
-        * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
-        * - mask passed in arg for lines of interest
-        *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
-        * Caller should use TIOCGICOUNT to see which one it was
-        */
-       case TIOCMIWAIT:
-               spin_lock_irqsave(&info->lock, flags);
-               cprev = info->icount;   /* note the counters on entry */
-               spin_unlock_irqrestore(&info->lock, flags);
-               while (1) {
-                       /* FIXME: convert to new style wakeup */
-                       interruptible_sleep_on(&info->port.delta_msr_wait);
-                       /* see if a signal did it */
-                       if (signal_pending(current))
-                               return -ERESTARTSYS;
-                       spin_lock_irqsave(&info->lock, flags);
-                       cnow = info->icount;    /* atomic copy */
-                       spin_unlock_irqrestore(&info->lock, flags);
-                       if (cnow.rng == cprev.rng &&
-                           cnow.dsr == cprev.dsr &&
-                           cnow.dcd == cprev.dcd &&
-                           cnow.cts == cprev.cts)
-                               return -EIO; /* no change => error */
-                       if (((arg & TIOCM_RNG) &&
-                            (cnow.rng != cprev.rng)) ||
-                            ((arg & TIOCM_DSR) &&
-                             (cnow.dsr != cprev.dsr)) ||
-                            ((arg & TIOCM_CD) &&
-                             (cnow.dcd != cprev.dcd)) ||
-                            ((arg & TIOCM_CTS) &&
-                             (cnow.cts != cprev.cts))) {
-                               return 0;
-                       }
-                       cprev = cnow;
-               }
-               /* NOTREACHED */
-       /*
-        * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
-        * Return: write counters to the user passed counter struct
-        * NB: both 1->0 and 0->1 transitions are counted except for
-        *     RI where only 0->1 is counted.
-        */
-       case TIOCGICOUNT:
-               spin_lock_irqsave(&info->lock, flags);
-               cnow = info->icount;
-               spin_unlock_irqrestore(&info->lock, flags);
-               p_cuser = argp;
-               if (put_user(cnow.cts, &p_cuser->cts) ||
-                   put_user(cnow.dsr, &p_cuser->dsr) ||
-                   put_user(cnow.rng, &p_cuser->rng) ||
-                   put_user(cnow.dcd, &p_cuser->dcd))
-                       return -EFAULT;
-                       return 0;
-       case TIOCGHAYESESP:
-               return get_esp_config(info, argp);
-       case TIOCSHAYESESP:
-               lock_kernel();
-               ret = set_esp_config(info, argp);
-               unlock_kernel();
-               return ret;
-       default:
-               return -ENOIOCTLCMD;
-       }
-       return 0;
-}
-
-static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
-{
-       struct esp_struct *info = tty->driver_data;
-       unsigned long flags;
-
-       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);
-               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);
-       }
-
-       /* 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);
-               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);
-       }
-
-       spin_unlock_irqrestore(&info->lock, flags);
-
-       /* Handle turning of CRTSCTS */
-       if ((old_termios->c_cflag & CRTSCTS) &&
-           !(tty->termios->c_cflag & CRTSCTS)) {
-               rs_start(tty);
-       }
-}
-
-/*
- * ------------------------------------------------------------
- * rs_close()
- *
- * This routine is called when the serial port gets closed.  First, we
- * wait for the last remaining data to be sent.  Then, we unlink its
- * async structure from the interrupt chain if necessary, and we free
- * that IRQ if nothing is left in the chain.
- * ------------------------------------------------------------
- */
-static void rs_close(struct tty_struct *tty, struct file *filp)
-{
-       struct esp_struct *info = tty->driver_data;
-       unsigned long flags;
-
-       if (!info || serial_paranoia_check(info, tty->name, "rs_close"))
-               return;
-
-       spin_lock_irqsave(&info->lock, flags);
-
-       if (tty_hung_up_p(filp)) {
-               DBG_CNT("before DEC-hung");
-               goto out;
-       }
-
-#ifdef SERIAL_DEBUG_OPEN
-       printk(KERN_DEBUG "rs_close ttys%d, count = %d\n",
-                                               info->line, info->port.count);
-#endif
-       if (tty->count == 1 && info->port.count != 1) {
-               /*
-                * Uh, oh.  tty->count is 1, which means that the tty
-                * structure will be freed.  Info->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(KERN_DEBUG "rs_close: bad serial port count; tty->count is 1, info->port.count is %d\n", info->port.count);
-               info->port.count = 1;
-       }
-       if (--info->port.count < 0) {
-               printk(KERN_ERR "rs_close: bad serial port count for ttys%d: %d\n",
-                      info->line, info->port.count);
-               info->port.count = 0;
-       }
-       if (info->port.count) {
-               DBG_CNT("before DEC-2");
-               goto out;
-       }
-       info->port.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.
-        */
-       tty->closing = 1;
-       if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-               tty_wait_until_sent(tty, info->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->IER &= ~UART_IER_RLSI; */
-       info->IER &= ~UART_IER_RDI;
-       info->read_status_mask &= ~UART_LSR_DR;
-       if (info->port.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);
-
-               /* disable receive timeout */
-               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
-                * important if there is a transmit FIFO!
-                */
-               rs_wait_until_sent(tty, info->timeout);
-       }
-       shutdown(info);
-       rs_flush_buffer(tty);
-       tty_ldisc_flush(tty);
-       tty->closing = 0;
-       info->port.tty = NULL;
-
-       if (info->port.blocked_open) {
-               if (info->close_delay)
-                       msleep_interruptible(jiffies_to_msecs(info->close_delay));
-               wake_up_interruptible(&info->port.open_wait);
-       }
-       info->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
-       wake_up_interruptible(&info->port.close_wait);
-       return;
-
-out:
-       spin_unlock_irqrestore(&info->lock, flags);
-}
-
-static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
-{
-       struct esp_struct *info = tty->driver_data;
-       unsigned long orig_jiffies, char_time;
-       unsigned long flags;
-
-       if (serial_paranoia_check(info, tty->name, "rs_wait_until_sent"))
-               return;
-
-       orig_jiffies = jiffies;
-       char_time = ((info->timeout - HZ / 50) / 1024) / 5;
-
-       if (!char_time)
-               char_time = 1;
-
-       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)) {
-
-               spin_unlock_irqrestore(&info->lock, flags);
-               msleep_interruptible(jiffies_to_msecs(char_time));
-
-               if (signal_pending(current))
-                       return;
-
-               if (timeout && time_after(jiffies, orig_jiffies + timeout))
-                       return;
-
-               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);
-       }
-       spin_unlock_irqrestore(&info->lock, flags);
-       set_current_state(TASK_RUNNING);
-}
-
-/*
- * esp_hangup() --- called by tty_hangup() when a hangup is signaled.
- */
-static void esp_hangup(struct tty_struct *tty)
-{
-       struct esp_struct *info = tty->driver_data;
-
-       if (serial_paranoia_check(info, tty->name, "esp_hangup"))
-               return;
-
-       rs_flush_buffer(tty);
-       shutdown(info);
-       info->port.count = 0;
-       info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
-       info->port.tty = NULL;
-       wake_up_interruptible(&info->port.open_wait);
-}
-
-static int esp_carrier_raised(struct tty_port *port)
-{
-       struct esp_struct *info = container_of(port, struct esp_struct, port);
-       serial_out(info, UART_ESI_CMD1, ESI_GET_UART_STAT);
-       if (serial_in(info, UART_ESI_STAT2) & UART_MSR_DCD)
-               return 1;
-       return 0;
-}
-
-/*
- * ------------------------------------------------------------
- * esp_open() and friends
- * ------------------------------------------------------------
- */
-static int block_til_ready(struct tty_struct *tty, struct file *filp,
-                          struct esp_struct *info)
-{
-       DECLARE_WAITQUEUE(wait, current);
-       int             retval;
-       int             do_clocal = 0;
-       unsigned long   flags;
-       int             cd;
-       struct tty_port *port = &info->port;
-
-       /*
-        * If the device is in the middle of being closed, then block
-        * until it's done, and then try again.
-        */
-       if (tty_hung_up_p(filp) ||
-           (port->flags & ASYNC_CLOSING)) {
-               if (port->flags & ASYNC_CLOSING)
-                       interruptible_sleep_on(&port->close_wait);
-#ifdef SERIAL_DO_RESTART
-               if (port->flags & ASYNC_HUP_NOTIFY)
-                       return -EAGAIN;
-               else
-                       return -ERESTARTSYS;
-#else
-               return -EAGAIN;
-#endif
-       }
-
-       /*
-        * If non-blocking mode is set, or the port is not enabled,
-        * then make the check up front and then exit.
-        */
-       if ((filp->f_flags & O_NONBLOCK) ||
-           (tty->flags & (1 << TTY_IO_ERROR))) {
-               port->flags |= ASYNC_NORMAL_ACTIVE;
-               return 0;
-       }
-
-       if (tty->termios->c_cflag & CLOCAL)
-               do_clocal = 1;
-
-       /*
-        * 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, 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(&port->open_wait, &wait);
-#ifdef SERIAL_DEBUG_OPEN
-       printk(KERN_DEBUG "block_til_ready before block: ttys%d, count = %d\n",
-              info->line, port->count);
-#endif
-       spin_lock_irqsave(&info->lock, flags);
-       if (!tty_hung_up_p(filp))
-               port->count--;
-       port->blocked_open++;
-       while (1) {
-               if ((tty->termios->c_cflag & CBAUD)) {
-                       unsigned int scratch;
-
-                       serial_out(info, UART_ESI_CMD1, ESI_READ_UART);
-                       serial_out(info, UART_ESI_CMD2, UART_MCR);
-                       scratch = serial_in(info, UART_ESI_STAT1);
-                       serial_out(info, UART_ESI_CMD1, ESI_WRITE_UART);
-                       serial_out(info, UART_ESI_CMD2, UART_MCR);
-                       serial_out(info, UART_ESI_CMD2,
-                               scratch | UART_MCR_DTR | UART_MCR_RTS);
-               }
-               set_current_state(TASK_INTERRUPTIBLE);
-               if (tty_hung_up_p(filp) ||
-                   !(port->flags & ASYNC_INITIALIZED)) {
-#ifdef SERIAL_DO_RESTART
-                       if (port->flags & ASYNC_HUP_NOTIFY)
-                               retval = -EAGAIN;
-                       else
-                               retval = -ERESTARTSYS;
-#else
-                       retval = -EAGAIN;
-#endif
-                       break;
-               }
-
-               cd = tty_port_carrier_raised(port);
-
-               if (!(port->flags & ASYNC_CLOSING) &&
-                   (do_clocal))
-                       break;
-               if (signal_pending(current)) {
-                       retval = -ERESTARTSYS;
-                       break;
-               }
-#ifdef SERIAL_DEBUG_OPEN
-               printk(KERN_DEBUG "block_til_ready blocking: ttys%d, count = %d\n",
-                      info->line, port->count);
-#endif
-               spin_unlock_irqrestore(&info->lock, flags);
-               schedule();
-               spin_lock_irqsave(&info->lock, flags);
-       }
-       set_current_state(TASK_RUNNING);
-       remove_wait_queue(&port->open_wait, &wait);
-       if (!tty_hung_up_p(filp))
-               port->count++;
-       port->blocked_open--;
-       spin_unlock_irqrestore(&info->lock, flags);
-#ifdef SERIAL_DEBUG_OPEN
-       printk(KERN_DEBUG "block_til_ready after blocking: ttys%d, count = %d\n",
-              info->line, port->count);
-#endif
-       if (retval)
-               return retval;
-       port->flags |= ASYNC_NORMAL_ACTIVE;
-       return 0;
-}
-
-/*
- * This routine is called whenever a serial port is opened.  It
- * enables interrupts for a serial port, linking in its async structure into
- * the IRQ chain.   It also performs the serial-specific
- * initialization for the tty structure.
- */
-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))
-               return -ENODEV;
-
-       /* find the port in the chain */
-
-       info = ports;
-
-       while (info && (info->line != line))
-               info = info->next_port;
-
-       if (!info) {
-               serial_paranoia_check(info, tty->name, "esp_open");
-               return -ENODEV;
-       }
-
-#ifdef SERIAL_DEBUG_OPEN
-       printk(KERN_DEBUG "esp_open %s, count = %d\n", tty->name, info->port.count);
-#endif
-       spin_lock_irqsave(&info->lock, flags);
-       info->port.count++;
-       tty->driver_data = info;
-       info->port.tty = tty;
-
-       spin_unlock_irqrestore(&info->lock, flags);
-
-       /*
-        * Start up serial port
-        */
-       retval = startup(info);
-       if (retval)
-               return retval;
-
-       retval = block_til_ready(tty, filp, info);
-       if (retval) {
-#ifdef SERIAL_DEBUG_OPEN
-               printk(KERN_DEBUG "esp_open returning after block_til_ready with %d\n",
-                      retval);
-#endif
-               return retval;
-       }
-#ifdef SERIAL_DEBUG_OPEN
-       printk(KERN_DEBUG "esp_open %s successful...", tty->name);
-#endif
-       return 0;
-}
-
-/*
- * ---------------------------------------------------------------------
- * espserial_init() and friends
- *
- * espserial_init() is called at boot-time to initialize the serial driver.
- * ---------------------------------------------------------------------
- */
-
-/*
- * This routine prints out the appropriate serial driver version
- * number, and identifies which options were configured into this
- * driver.
- */
-
-static void __init show_serial_version(void)
-{
-       printk(KERN_INFO "%s version %s (DMA %u)\n",
-               serial_name, serial_version, dma);
-}
-
-/*
- * This routine is called by espserial_init() to initialize a specific serial
- * port.
- */
-static int autoconfig(struct esp_struct *info)
-{
-       int port_detected = 0;
-       unsigned long flags;
-
-       if (!request_region(info->io_port, REGION_SIZE, "esp serial"))
-               return -EIO;
-
-       spin_lock_irqsave(&info->lock, flags);
-       /*
-        * Check for ESP card
-        */
-
-       if (serial_in(info, UART_ESI_BASE) == 0xf3) {
-               serial_out(info, UART_ESI_CMD1, 0x00);
-               serial_out(info, UART_ESI_CMD1, 0x01);
-
-               if ((serial_in(info, UART_ESI_STAT2) & 0x70) == 0x20) {
-                       port_detected = 1;
-
-                       if (!(info->irq)) {
-                               serial_out(info, UART_ESI_CMD1, 0x02);
-
-                               if (serial_in(info, UART_ESI_STAT1) & 0x01)
-                                       info->irq = 3;
-                               else
-                                       info->irq = 4;
-                       }
-
-
-                       /* put card in enhanced mode */
-                       /* this prevents access through */
-                       /* the "old" IO ports */
-                       esp_basic_init(info);
-
-                       /* clear out MCR */
-                       serial_out(info, UART_ESI_CMD1, ESI_WRITE_UART);
-                       serial_out(info, UART_ESI_CMD2, UART_MCR);
-                       serial_out(info, UART_ESI_CMD2, 0x00);
-               }
-       }
-       if (!port_detected)
-               release_region(info->io_port, REGION_SIZE);
-
-       spin_unlock_irqrestore(&info->lock, flags);
-       return (port_detected);
-}
-
-static const struct tty_operations esp_ops = {
-       .open = esp_open,
-       .close = rs_close,
-       .write = rs_write,
-       .put_char = rs_put_char,
-       .flush_chars = rs_flush_chars,
-       .write_room = rs_write_room,
-       .chars_in_buffer = rs_chars_in_buffer,
-       .flush_buffer = rs_flush_buffer,
-       .ioctl = rs_ioctl,
-       .throttle = rs_throttle,
-       .unthrottle = rs_unthrottle,
-       .set_termios = rs_set_termios,
-       .stop = rs_stop,
-       .start = rs_start,
-       .hangup = esp_hangup,
-       .break_ctl = esp_break,
-       .wait_until_sent = rs_wait_until_sent,
-       .tiocmget = esp_tiocmget,
-       .tiocmset = esp_tiocmset,
-};
-
-static const struct tty_port_operations esp_port_ops = {
-       .esp_carrier_raised,
-};
-
-/*
- * The serial driver boot-time initialization code!
- */
-static int __init espserial_init(void)
-{
-       int i, offset;
-       struct esp_struct *info;
-       struct esp_struct *last_primary = NULL;
-       int esp[] = { 0x100, 0x140, 0x180, 0x200, 0x240, 0x280, 0x300, 0x380 };
-
-       esp_driver = alloc_tty_driver(NR_PORTS);
-       if (!esp_driver)
-               return -ENOMEM;
-
-       for (i = 0; i < NR_PRIMARY; i++) {
-               if (irq[i] != 0) {
-                       if ((irq[i] < 2) || (irq[i] > 15) || (irq[i] == 6) ||
-                           (irq[i] == 8) || (irq[i] == 13))
-                               irq[i] = 0;
-                       else if (irq[i] == 2)
-                               irq[i] = 9;
-               }
-       }
-
-       if ((dma != 1) && (dma != 3))
-               dma = 0;
-
-       if ((rx_trigger < 1) || (rx_trigger > 1023))
-               rx_trigger = 768;
-
-       if ((tx_trigger < 1) || (tx_trigger > 1023))
-               tx_trigger = 768;
-
-       if ((flow_off < 1) || (flow_off > 1023))
-               flow_off = 1016;
-
-       if ((flow_on < 1) || (flow_on > 1023))
-               flow_on = 944;
-
-       if ((rx_timeout < 0) || (rx_timeout > 255))
-               rx_timeout = 128;
-
-       if (flow_on >= flow_off)
-               flow_on = flow_off - 1;
-
-       show_serial_version();
-
-       /* Initialize the tty_driver structure */
-
-       esp_driver->owner = THIS_MODULE;
-       esp_driver->name = "ttyP";
-       esp_driver->major = ESP_IN_MAJOR;
-       esp_driver->minor_start = 0;
-       esp_driver->type = TTY_DRIVER_TYPE_SERIAL;
-       esp_driver->subtype = SERIAL_TYPE_NORMAL;
-       esp_driver->init_termios = tty_std_termios;
-       esp_driver->init_termios.c_cflag =
-               B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-       esp_driver->init_termios.c_ispeed = 9600;
-       esp_driver->init_termios.c_ospeed = 9600;
-       esp_driver->flags = TTY_DRIVER_REAL_RAW;
-       tty_set_operations(esp_driver, &esp_ops);
-       if (tty_register_driver(esp_driver)) {
-               printk(KERN_ERR "Couldn't register esp serial driver");
-               put_tty_driver(esp_driver);
-               return 1;
-       }
-
-       info = kzalloc(sizeof(struct esp_struct), GFP_KERNEL);
-
-       if (!info) {
-               printk(KERN_ERR "Couldn't allocate memory for esp serial device information\n");
-               tty_unregister_driver(esp_driver);
-               put_tty_driver(esp_driver);
-               return 1;
-       }
-
-       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;
-
-       i = 0;
-       offset = 0;
-
-       do {
-               tty_port_init(&info->port);
-               info->port.ops = &esp_port_ops;
-               info->io_port = esp[i] + offset;
-               info->irq = irq[i];
-               info->line = (i * 8) + (offset / 8);
-
-               if (!autoconfig(info)) {
-                       i++;
-                       offset = 0;
-                       continue;
-               }
-
-               info->custom_divisor = (divisor[i] >> (offset / 2)) & 0xf;
-               info->port.flags = STD_COM_FLAGS;
-               if (info->custom_divisor)
-                       info->port.flags |= ASYNC_SPD_CUST;
-               info->magic = ESP_MAGIC;
-               info->close_delay = 5*HZ/10;
-               info->closing_wait = 30*HZ;
-               info->config.rx_timeout = rx_timeout;
-               info->config.flow_on = flow_on;
-               info->config.flow_off = flow_off;
-               info->config.pio_threshold = pio_threshold;
-               info->next_port = ports;
-               init_waitqueue_head(&info->break_wait);
-               ports = info;
-               printk(KERN_INFO "ttyP%d at 0x%04x (irq = %d) is an ESP ",
-                       info->line, info->io_port, info->irq);
-
-               if (info->line % 8) {
-                       printk("secondary port\n");
-                       /* 8 port cards can't do DMA */
-                       info->stat_flags |= ESP_STAT_NEVER_DMA;
-
-                       if (last_primary)
-                               last_primary->stat_flags |= ESP_STAT_NEVER_DMA;
-               } else {
-                       printk("primary port\n");
-                       last_primary = info;
-                       irq[i] = info->irq;
-               }
-
-               if (!dma)
-                       info->stat_flags |= ESP_STAT_NEVER_DMA;
-
-               info = kzalloc(sizeof(struct esp_struct), GFP_KERNEL);
-               if (!info) {
-                       printk(KERN_ERR "Couldn't allocate memory for esp serial device information\n");
-                       /* allow use of the already detected ports */
-                       return 0;
-               }
-
-               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;
-
-               if (offset == 56) {
-                       i++;
-                       offset = 0;
-               } else {
-                       offset += 8;
-               }
-       } while (i < NR_PRIMARY);
-
-       /* free the last port memory allocation */
-       kfree(info);
-
-       return 0;
-}
-
-static void __exit espserial_exit(void)
-{
-       int e1;
-       struct esp_struct *temp_async;
-       struct esp_pio_buffer *pio_buf;
-
-       e1 = tty_unregister_driver(esp_driver);
-       if (e1)
-               printk(KERN_ERR "esp: failed to unregister driver (%d)\n", e1);
-       put_tty_driver(esp_driver);
-
-       while (ports) {
-               if (ports->io_port)
-                       release_region(ports->io_port, REGION_SIZE);
-               temp_async = ports->next_port;
-               kfree(ports);
-               ports = temp_async;
-       }
-
-       if (dma_buffer)
-               free_pages((unsigned long)dma_buffer,
-                       get_order(DMA_BUFFER_SZ));
-
-       while (free_pio_buf) {
-               pio_buf = free_pio_buf->next;
-               kfree(free_pio_buf);
-               free_pio_buf = pio_buf;
-       }
-}
-
-module_init(espserial_init);
-module_exit(espserial_exit);
index 426bfdd7f3e0221d07498f7b30c9aab7d6904a48..300d5bd6cd0602fc57f160d00757d64fb49e2e6a 100644 (file)
@@ -793,35 +793,30 @@ static inline void isicom_setup_board(struct isi_board *bp)
 {
        int channel;
        struct isi_port *port;
-       unsigned long flags;
 
-       spin_lock_irqsave(&bp->card_lock, flags);
-       if (bp->status & BOARD_ACTIVE) {
-               spin_unlock_irqrestore(&bp->card_lock, flags);
-               return;
+       bp->count++;
+       if (!(bp->status & BOARD_INIT)) {
+               port = bp->ports;
+               for (channel = 0; channel < bp->port_count; channel++, port++)
+                       drop_dtr_rts(port);
        }
-       port = bp->ports;
-       bp->status |= BOARD_ACTIVE;
-       for (channel = 0; channel < bp->port_count; channel++, port++)
-               drop_dtr_rts(port);
-       spin_unlock_irqrestore(&bp->card_lock, flags);
+       bp->status |= BOARD_ACTIVE | BOARD_INIT;
 }
 
-static int isicom_setup_port(struct tty_struct *tty)
+/* Activate and thus setup board are protected from races against shutdown
+   by the tty_port mutex */
+
+static int isicom_activate(struct tty_port *tport, struct tty_struct *tty)
 {
-       struct isi_port *port = tty->driver_data;
+       struct isi_port *port = container_of(tport, struct isi_port, port);
        struct isi_board *card = port->card;
        unsigned long flags;
 
-       if (port->port.flags & ASYNC_INITIALIZED)
-               return 0;
-       if (tty_port_alloc_xmit_buf(&port->port) < 0)
+       if (tty_port_alloc_xmit_buf(tport) < 0)
                return -ENOMEM;
 
        spin_lock_irqsave(&card->card_lock, flags);
-       clear_bit(TTY_IO_ERROR, &tty->flags);
-       if (port->port.count == 1)
-               card->count++;
+       isicom_setup_board(card);
 
        port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
 
@@ -832,9 +827,7 @@ static int isicom_setup_port(struct tty_struct *tty)
                outw(((ISICOM_KILLTX | ISICOM_KILLRX) << 8) | 0x06, card->base);
                InterruptTheCard(card->base);
        }
-
        isicom_config_port(tty);
-       port->port.flags |= ASYNC_INITIALIZED;
        spin_unlock_irqrestore(&card->card_lock, flags);
 
        return 0;
@@ -871,85 +864,37 @@ static struct tty_port *isicom_find_port(struct tty_struct *tty)
 
        return &port->port;
 }
-       
+
 static int isicom_open(struct tty_struct *tty, struct file *filp)
 {
        struct isi_port *port;
        struct isi_board *card;
        struct tty_port *tport;
-       int error = 0;
 
        tport = isicom_find_port(tty);
        if (tport == NULL)
                return -ENODEV;
        port = container_of(tport, struct isi_port, port);
        card = &isi_card[BOARD(tty->index)];
-       isicom_setup_board(card);
 
-       /* FIXME: locking on port.count etc */
-       port->port.count++;
-       tty->driver_data = port;
-       tty_port_tty_set(&port->port, tty);
-       /* FIXME: Locking on Initialized flag */
-       if (!test_bit(ASYNCB_INITIALIZED, &tport->flags))
-               error = isicom_setup_port(tty);
-       if (error == 0)
-               error = tty_port_block_til_ready(&port->port, tty, filp);
-       return error;
+       return tty_port_open(tport, tty, filp);
 }
 
 /* close et all */
 
-static inline void isicom_shutdown_board(struct isi_board *bp)
-{
-       if (bp->status & BOARD_ACTIVE)
-               bp->status &= ~BOARD_ACTIVE;
-}
-
 /* card->lock HAS to be held */
 static void isicom_shutdown_port(struct isi_port *port)
 {
        struct isi_board *card = port->card;
-       struct tty_struct *tty;
-
-       tty = tty_port_tty_get(&port->port);
-
-       if (!(port->port.flags & ASYNC_INITIALIZED)) {
-               tty_kref_put(tty);
-               return;
-       }
-
-       tty_port_free_xmit_buf(&port->port);
-       port->port.flags &= ~ASYNC_INITIALIZED;
-       /* 3rd October 2000 : Vinayak P Risbud */
-       tty_port_tty_set(&port->port, NULL);
-
-       /*Fix done by Anil .S on 30-04-2001
-       remote login through isi port has dtr toggle problem
-       due to which the carrier drops before the password prompt
-       appears on the remote end. Now we drop the dtr only if the
-       HUPCL(Hangup on close) flag is set for the tty*/
-
-       if (C_HUPCL(tty))
-               /* drop dtr on this port */
-               drop_dtr(port);
-
-       /* any other port uninits  */
-       if (tty)
-               set_bit(TTY_IO_ERROR, &tty->flags);
 
        if (--card->count < 0) {
                pr_dbg("isicom_shutdown_port: bad board(0x%lx) count %d.\n",
                        card->base, card->count);
                card->count = 0;
        }
-
-       /* last port was closed, shutdown that boad too */
-       if (C_HUPCL(tty)) {
-               if (!card->count)
-                       isicom_shutdown_board(card);
-       }
-       tty_kref_put(tty);
+       /* last port was closed, shutdown that board too */
+       if (!card->count)
+               card->status &= BOARD_ACTIVE;
 }
 
 static void isicom_flush_buffer(struct tty_struct *tty)
@@ -968,7 +913,7 @@ static void isicom_flush_buffer(struct tty_struct *tty)
        tty_wakeup(tty);
 }
 
-static void isicom_close_port(struct tty_port *port)
+static void isicom_shutdown(struct tty_port *port)
 {
        struct isi_port *ip = container_of(port, struct isi_port, port);
        struct isi_board *card = ip->card;
@@ -977,12 +922,11 @@ static void isicom_close_port(struct tty_port *port)
        /* indicate to the card that no more data can be received
           on this port */
        spin_lock_irqsave(&card->card_lock, flags);
-       if (port->flags & ASYNC_INITIALIZED) {
-               card->port_status &= ~(1 << ip->channel);
-               outw(card->port_status, card->base + 0x02);
-       }
+       card->port_status &= ~(1 << ip->channel);
+       outw(card->port_status, card->base + 0x02);
        isicom_shutdown_port(ip);
        spin_unlock_irqrestore(&card->card_lock, flags);
+       tty_port_free_xmit_buf(port);
 }
 
 static void isicom_close(struct tty_struct *tty, struct file *filp)
@@ -991,12 +935,7 @@ static void isicom_close(struct tty_struct *tty, struct file *filp)
        struct tty_port *port = &ip->port;
        if (isicom_paranoia_check(ip, tty->name, "isicom_close"))
                return;
-
-       if (tty_port_close_start(port, tty, filp) == 0)
-               return;
-       isicom_close_port(port);
-       isicom_flush_buffer(tty);
-       tty_port_close_end(port, tty);
+       tty_port_close(port, tty, filp);
 }
 
 /* write et all */
@@ -1326,15 +1265,9 @@ static void isicom_start(struct tty_struct *tty)
 static void isicom_hangup(struct tty_struct *tty)
 {
        struct isi_port *port = tty->driver_data;
-       unsigned long flags;
 
        if (isicom_paranoia_check(port, tty->name, "isicom_hangup"))
                return;
-
-       spin_lock_irqsave(&port->card->card_lock, flags);
-       isicom_shutdown_port(port);
-       spin_unlock_irqrestore(&port->card->card_lock, flags);
-
        tty_port_hangup(&port->port);
 }
 
@@ -1367,6 +1300,8 @@ static const struct tty_operations isicom_ops = {
 static const struct tty_port_operations isicom_port_ops = {
        .carrier_raised         = isicom_carrier_raised,
        .dtr_rts                = isicom_dtr_rts,
+       .activate               = isicom_activate,
+       .shutdown               = isicom_shutdown,
 };
 
 static int __devinit reset_card(struct pci_dev *pdev,
index 402838f4083e31091fe2480490c8a3ac0e42efa6..4cd6c527ee4141929c2257e9798a7c51cab45a6b 100644 (file)
@@ -213,7 +213,6 @@ static int          stli_shared;
  *     with the slave. Most of them need to be updated atomically, so always
  *     use the bit setting operations (unless protected by cli/sti).
  */
-#define        ST_INITIALIZING 1
 #define        ST_OPENING      2
 #define        ST_CLOSING      3
 #define        ST_CMDING       4
@@ -621,7 +620,7 @@ static int  stli_brdinit(struct stlibrd *brdp);
 static int     stli_startbrd(struct stlibrd *brdp);
 static ssize_t stli_memread(struct file *fp, char __user *buf, size_t count, loff_t *offp);
 static ssize_t stli_memwrite(struct file *fp, const char __user *buf, size_t count, loff_t *offp);
-static int     stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg);
+static long    stli_memioctl(struct file *fp, unsigned int cmd, unsigned long arg);
 static void    stli_brdpoll(struct stlibrd *brdp, cdkhdr_t __iomem *hdrp);
 static void    stli_poll(unsigned long arg);
 static int     stli_hostcmd(struct stlibrd *brdp, struct stliport *portp);
@@ -704,7 +703,7 @@ static const struct file_operations stli_fsiomem = {
        .owner          = THIS_MODULE,
        .read           = stli_memread,
        .write          = stli_memwrite,
-       .ioctl          = stli_memioctl,
+       .unlocked_ioctl = stli_memioctl,
 };
 
 /*****************************************************************************/
@@ -783,13 +782,32 @@ static int stli_parsebrd(struct stlconf *confp, char **argp)
 
 /*****************************************************************************/
 
+/*
+ *     On the first open of the device setup the port hardware, and
+ *     initialize the per port data structure. Since initializing the port
+ *     requires several commands to the board we will need to wait for any
+ *     other open that is already initializing the port.
+ *
+ *     Locking: protected by the port mutex.
+ */
+
+static int stli_activate(struct tty_port *port, struct tty_struct *tty)
+{
+       struct stliport *portp = container_of(port, struct stliport, port);
+       struct stlibrd *brdp = stli_brds[portp->brdnr];
+       int rc;
+
+       if ((rc = stli_initopen(tty, brdp, portp)) >= 0)
+               clear_bit(TTY_IO_ERROR, &tty->flags);
+       wake_up_interruptible(&portp->raw_wait);
+       return rc;
+}
+
 static int stli_open(struct tty_struct *tty, struct file *filp)
 {
        struct stlibrd *brdp;
        struct stliport *portp;
-       struct tty_port *port;
        unsigned int minordev, brdnr, portnr;
-       int rc;
 
        minordev = tty->index;
        brdnr = MINOR2BRD(minordev);
@@ -809,95 +827,56 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
                return -ENODEV;
        if (portp->devnr < 1)
                return -ENODEV;
-       port = &portp->port;
-
-/*
- *     On the first open of the device setup the port hardware, and
- *     initialize the per port data structure. Since initializing the port
- *     requires several commands to the board we will need to wait for any
- *     other open that is already initializing the port.
- *
- *     Review - locking
- */
-       tty_port_tty_set(port, tty);
-       tty->driver_data = portp;
-       port->count++;
-
-       wait_event_interruptible(portp->raw_wait,
-                       !test_bit(ST_INITIALIZING, &portp->state));
-       if (signal_pending(current))
-               return -ERESTARTSYS;
-
-       if ((portp->port.flags & ASYNC_INITIALIZED) == 0) {
-               set_bit(ST_INITIALIZING, &portp->state);
-               if ((rc = stli_initopen(tty, brdp, portp)) >= 0) {
-                       /* Locking */
-                       port->flags |= ASYNC_INITIALIZED;
-                       clear_bit(TTY_IO_ERROR, &tty->flags);
-               }
-               clear_bit(ST_INITIALIZING, &portp->state);
-               wake_up_interruptible(&portp->raw_wait);
-               if (rc < 0)
-                       return rc;
-       }
-       return tty_port_block_til_ready(&portp->port, tty, filp);
+       return tty_port_open(&portp->port, tty, filp);
 }
 
+
 /*****************************************************************************/
 
-static void stli_close(struct tty_struct *tty, struct file *filp)
+static void stli_shutdown(struct tty_port *port)
 {
        struct stlibrd *brdp;
-       struct stliport *portp;
-       struct tty_port *port;
+       unsigned long ftype;
        unsigned long flags;
+       struct stliport *portp = container_of(port, struct stliport, port);
 
-       portp = tty->driver_data;
-       if (portp == NULL)
+       if (portp->brdnr >= stli_nrbrds)
                return;
-       port = &portp->port;
-
-       if (tty_port_close_start(port, tty, filp) == 0)
+       brdp = stli_brds[portp->brdnr];
+       if (brdp == NULL)
                return;
 
-/*
- *     May want to wait for data to drain before closing. The BUSY flag
- *     keeps track of whether we are still transmitting or not. It is
- *     updated by messages from the slave - indicating when all chars
- *     really have drained.
- */
-       spin_lock_irqsave(&stli_lock, flags);
-       if (tty == stli_txcooktty)
-               stli_flushchars(tty);
-       spin_unlock_irqrestore(&stli_lock, flags);
-
-       /* We end up doing this twice for the moment. This needs looking at
-          eventually. Note we still use portp->closing_wait as a result */
-       if (portp->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-               tty_wait_until_sent(tty, portp->closing_wait);
+       /*
+        *      May want to wait for data to drain before closing. The BUSY
+        *      flag keeps track of whether we are still transmitting or not.
+        *      It is updated by messages from the slave - indicating when all
+        *      chars really have drained.
+        */
 
-       /* FIXME: port locking here needs attending to */
-       port->flags &= ~ASYNC_INITIALIZED;
+       if (!test_bit(ST_CLOSING, &portp->state))
+               stli_rawclose(brdp, portp, 0, 0);
 
-       brdp = stli_brds[portp->brdnr];
-       stli_rawclose(brdp, portp, 0, 0);
-       if (tty->termios->c_cflag & HUPCL) {
-               stli_mkasysigs(&portp->asig, 0, 0);
-               if (test_bit(ST_CMDING, &portp->state))
-                       set_bit(ST_DOSIGS, &portp->state);
-               else
-                       stli_sendcmd(brdp, portp, A_SETSIGNALS, &portp->asig,
-                               sizeof(asysigs_t), 0);
-       }
+       spin_lock_irqsave(&stli_lock, flags);
        clear_bit(ST_TXBUSY, &portp->state);
        clear_bit(ST_RXSTOP, &portp->state);
-       set_bit(TTY_IO_ERROR, &tty->flags);
-       tty_ldisc_flush(tty);
-       set_bit(ST_DOFLUSHRX, &portp->state);
-       stli_flushbuffer(tty);
+       spin_unlock_irqrestore(&stli_lock, flags);
 
-       tty_port_close_end(port, tty);
-       tty_port_tty_set(port, NULL);
+       ftype = FLUSHTX | FLUSHRX;
+       stli_cmdwait(brdp, portp, A_FLUSH, &ftype, sizeof(u32), 0);
+}
+
+static void stli_close(struct tty_struct *tty, struct file *filp)
+{
+       struct stliport *portp = tty->driver_data;
+       unsigned long flags;
+       if (portp == NULL)
+               return;
+       spin_lock_irqsave(&stli_lock, flags);
+       /*      Flush any internal buffering out first */
+       if (tty == stli_txcooktty)
+               stli_flushchars(tty);
+       spin_unlock_irqrestore(&stli_lock, flags);
+       tty_port_close(&portp->port, tty, filp);
 }
 
 /*****************************************************************************/
@@ -1724,6 +1703,7 @@ static void stli_start(struct tty_struct *tty)
 
 /*****************************************************************************/
 
+
 /*
  *     Hangup this port. This is pretty much like closing the port, only
  *     a little more brutal. No waiting for data to drain. Shutdown the
@@ -1733,47 +1713,8 @@ static void stli_start(struct tty_struct *tty)
 
 static void stli_hangup(struct tty_struct *tty)
 {
-       struct stliport *portp;
-       struct stlibrd *brdp;
-       struct tty_port *port;
-       unsigned long flags;
-
-       portp = tty->driver_data;
-       if (portp == NULL)
-               return;
-       if (portp->brdnr >= stli_nrbrds)
-               return;
-       brdp = stli_brds[portp->brdnr];
-       if (brdp == NULL)
-               return;
-       port = &portp->port;
-
-       spin_lock_irqsave(&port->lock, flags);
-       port->flags &= ~ASYNC_INITIALIZED;
-       spin_unlock_irqrestore(&port->lock, flags);
-
-       if (!test_bit(ST_CLOSING, &portp->state))
-               stli_rawclose(brdp, portp, 0, 0);
-
-       spin_lock_irqsave(&stli_lock, flags);
-       if (tty->termios->c_cflag & HUPCL) {
-               stli_mkasysigs(&portp->asig, 0, 0);
-               if (test_bit(ST_CMDING, &portp->state)) {
-                       set_bit(ST_DOSIGS, &portp->state);
-                       set_bit(ST_DOFLUSHTX, &portp->state);
-                       set_bit(ST_DOFLUSHRX, &portp->state);
-               } else {
-                       stli_sendcmd(brdp, portp, A_SETSIGNALSF,
-                               &portp->asig, sizeof(asysigs_t), 0);
-               }
-       }
-
-       clear_bit(ST_TXBUSY, &portp->state);
-       clear_bit(ST_RXSTOP, &portp->state);
-       set_bit(TTY_IO_ERROR, &tty->flags);
-       spin_unlock_irqrestore(&stli_lock, flags);
-
-       tty_port_hangup(port);
+       struct stliport *portp = tty->driver_data;
+       tty_port_hangup(&portp->port);
 }
 
 /*****************************************************************************/
@@ -4311,7 +4252,7 @@ static int stli_getbrdstruct(struct stlibrd __user *arg)
  *     reset it, and start/stop it.
  */
 
-static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg)
+static long stli_memioctl(struct file *fp, unsigned int cmd, unsigned long arg)
 {
        struct stlibrd *brdp;
        int brdnr, rc, done;
@@ -4356,7 +4297,7 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un
  *     Now handle the board specific ioctls. These all depend on the
  *     minor number of the device they were called from.
  */
-       brdnr = iminor(ip);
+       brdnr = iminor(fp->f_dentry->d_inode);
        if (brdnr >= STL_MAXBRDS)
                return -ENODEV;
        brdp = stli_brds[brdnr];
@@ -4420,6 +4361,8 @@ static const struct tty_operations stli_ops = {
 static const struct tty_port_operations stli_port_ops = {
        .carrier_raised = stli_carrier_raised,
        .dtr_rts = stli_dtr_rts,
+       .activate = stli_activate,
+       .shutdown = stli_shutdown,
 };
 
 /*****************************************************************************/
index dd0083bbb64addaea9b286ac8d5a914a474625ea..63ee3bbc1ce4169654624980c3281e28fe84ae7c 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
 #include <linux/major.h>
-#include <linux/smp_lock.h>
 #include <linux/string.h>
 #include <linux/fcntl.h>
 #include <linux/ptrace.h>
@@ -139,7 +138,7 @@ struct moxa_port {
        int cflag;
        unsigned long statusflags;
 
-       u8 DCDState;
+       u8 DCDState;            /* Protected by the port lock */
        u8 lineCtrl;
        u8 lowChkFlag;
 };
@@ -151,10 +150,9 @@ struct mon_str {
 };
 
 /* statusflags */
-#define TXSTOPPED      0x1
-#define LOWWAIT        0x2
-#define EMPTYWAIT      0x4
-#define THROTTLE       0x8
+#define TXSTOPPED      1
+#define LOWWAIT        2
+#define EMPTYWAIT      3
 
 #define SERIAL_DO_RESTART
 
@@ -165,6 +163,7 @@ static struct mon_str moxaLog;
 static unsigned int moxaFuncTout = HZ / 2;
 static unsigned int moxaLowWaterChk;
 static DEFINE_MUTEX(moxa_openlock);
+static DEFINE_SPINLOCK(moxa_lock);
 /* Variables for insmod */
 #ifdef MODULE
 static unsigned long baseaddr[MAX_BOARDS];
@@ -194,8 +193,6 @@ static int moxa_write(struct tty_struct *, const unsigned char *, int);
 static int moxa_write_room(struct tty_struct *);
 static void moxa_flush_buffer(struct tty_struct *);
 static int moxa_chars_in_buffer(struct tty_struct *);
-static void moxa_throttle(struct tty_struct *);
-static void moxa_unthrottle(struct tty_struct *);
 static void moxa_set_termios(struct tty_struct *, struct ktermios *);
 static void moxa_stop(struct tty_struct *);
 static void moxa_start(struct tty_struct *);
@@ -205,9 +202,9 @@ static int moxa_tiocmset(struct tty_struct *tty, struct file *file,
                         unsigned int set, unsigned int clear);
 static void moxa_poll(unsigned long);
 static void moxa_set_tty_param(struct tty_struct *, struct ktermios *);
-static void moxa_setup_empty_event(struct tty_struct *);
-static void moxa_shut_down(struct tty_struct *);
+static void moxa_shutdown(struct tty_port *);
 static int moxa_carrier_raised(struct tty_port *);
+static void moxa_dtr_rts(struct tty_port *, int);
 /*
  * moxa board interface functions:
  */
@@ -234,6 +231,8 @@ static void MoxaSetFifo(struct moxa_port *port, int enable);
  * I/O functions
  */
 
+static DEFINE_SPINLOCK(moxafunc_lock);
+
 static void moxa_wait_finish(void __iomem *ofsAddr)
 {
        unsigned long end = jiffies + moxaFuncTout;
@@ -247,9 +246,25 @@ static void moxa_wait_finish(void __iomem *ofsAddr)
 
 static void moxafunc(void __iomem *ofsAddr, u16 cmd, u16 arg)
 {
+        unsigned long flags;
+        spin_lock_irqsave(&moxafunc_lock, flags);
        writew(arg, ofsAddr + FuncArg);
        writew(cmd, ofsAddr + FuncCode);
        moxa_wait_finish(ofsAddr);
+       spin_unlock_irqrestore(&moxafunc_lock, flags);
+}
+
+static int moxafuncret(void __iomem *ofsAddr, u16 cmd, u16 arg)
+{
+        unsigned long flags;
+        u16 ret;
+        spin_lock_irqsave(&moxafunc_lock, flags);
+       writew(arg, ofsAddr + FuncArg);
+       writew(cmd, ofsAddr + FuncCode);
+       moxa_wait_finish(ofsAddr);
+       ret = readw(ofsAddr + FuncArg);
+       spin_unlock_irqrestore(&moxafunc_lock, flags);
+       return ret;
 }
 
 static void moxa_low_water_check(void __iomem *ofsAddr)
@@ -299,22 +314,20 @@ static int moxa_ioctl(struct tty_struct *tty, struct file *file,
                struct moxa_port *p;
                unsigned int i, j;
 
-               mutex_lock(&moxa_openlock);
                for (i = 0; i < MAX_BOARDS; i++) {
                        p = moxa_boards[i].ports;
                        for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) {
                                memset(&tmp, 0, sizeof(tmp));
+                               spin_lock_bh(&moxa_lock);
                                if (moxa_boards[i].ready) {
                                        tmp.inq = MoxaPortRxQueue(p);
                                        tmp.outq = MoxaPortTxQueue(p);
                                }
-                               if (copy_to_user(argm, &tmp, sizeof(tmp))) {
-                                       mutex_unlock(&moxa_openlock);
+                               spin_unlock_bh(&moxa_lock);
+                               if (copy_to_user(argm, &tmp, sizeof(tmp)))
                                        return -EFAULT;
-                               }
                        }
                }
-               mutex_unlock(&moxa_openlock);
                break;
        } case MOXA_GET_OQUEUE:
                status = MoxaPortTxQueue(ch);
@@ -330,16 +343,20 @@ static int moxa_ioctl(struct tty_struct *tty, struct file *file,
                struct moxa_port *p;
                unsigned int i, j;
 
-               mutex_lock(&moxa_openlock);
                for (i = 0; i < MAX_BOARDS; i++) {
                        p = moxa_boards[i].ports;
                        for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) {
                                struct tty_struct *ttyp;
                                memset(&tmp, 0, sizeof(tmp));
-                               if (!moxa_boards[i].ready)
+                               spin_lock_bh(&moxa_lock);
+                               if (!moxa_boards[i].ready) {
+                                       spin_unlock_bh(&moxa_lock);
                                        goto copy;
+                                }
 
                                status = MoxaPortLineStatus(p);
+                               spin_unlock_bh(&moxa_lock);
+
                                if (status & 1)
                                        tmp.cts = 1;
                                if (status & 2)
@@ -354,24 +371,21 @@ static int moxa_ioctl(struct tty_struct *tty, struct file *file,
                                        tmp.cflag = ttyp->termios->c_cflag;
                                tty_kref_put(tty);
 copy:
-                               if (copy_to_user(argm, &tmp, sizeof(tmp))) {
-                                       mutex_unlock(&moxa_openlock);
+                               if (copy_to_user(argm, &tmp, sizeof(tmp)))
                                        return -EFAULT;
-                               }
                        }
                }
-               mutex_unlock(&moxa_openlock);
                break;
        }
        case TIOCGSERIAL:
-               mutex_lock(&moxa_openlock);
+               mutex_lock(&ch->port.mutex);
                ret = moxa_get_serial_info(ch, argp);
-               mutex_unlock(&moxa_openlock);
+               mutex_unlock(&ch->port.mutex);
                break;
        case TIOCSSERIAL:
-               mutex_lock(&moxa_openlock);
+               mutex_lock(&ch->port.mutex);
                ret = moxa_set_serial_info(ch, argp);
-               mutex_unlock(&moxa_openlock);
+               mutex_unlock(&ch->port.mutex);
                break;
        default:
                ret = -ENOIOCTLCMD;
@@ -396,8 +410,6 @@ static const struct tty_operations moxa_ops = {
        .flush_buffer = moxa_flush_buffer,
        .chars_in_buffer = moxa_chars_in_buffer,
        .ioctl = moxa_ioctl,
-       .throttle = moxa_throttle,
-       .unthrottle = moxa_unthrottle,
        .set_termios = moxa_set_termios,
        .stop = moxa_stop,
        .start = moxa_start,
@@ -409,11 +421,12 @@ static const struct tty_operations moxa_ops = {
 
 static const struct tty_port_operations moxa_port_ops = {
        .carrier_raised = moxa_carrier_raised,
+       .dtr_rts = moxa_dtr_rts,
+       .shutdown = moxa_shutdown,
 };
 
 static struct tty_driver *moxaDriver;
 static DEFINE_TIMER(moxaTimer, moxa_poll, 0, 0);
-static DEFINE_SPINLOCK(moxa_lock);
 
 /*
  * HW init
@@ -1112,14 +1125,12 @@ static void __exit moxa_exit(void)
 module_init(moxa_init);
 module_exit(moxa_exit);
 
-static void moxa_close_port(struct tty_struct *tty)
+static void moxa_shutdown(struct tty_port *port)
 {
-       struct moxa_port *ch = tty->driver_data;
-       moxa_shut_down(tty);
+       struct moxa_port *ch = container_of(port, struct moxa_port, port);
+        MoxaPortDisable(ch);
        MoxaPortFlushData(ch, 2);
-       ch->port.flags &= ~ASYNC_NORMAL_ACTIVE;
-       tty->driver_data = NULL;
-       tty_port_tty_set(&ch->port, NULL);
+       clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags);
 }
 
 static int moxa_carrier_raised(struct tty_port *port)
@@ -1127,45 +1138,19 @@ static int moxa_carrier_raised(struct tty_port *port)
        struct moxa_port *ch = container_of(port, struct moxa_port, port);
        int dcd;
 
-       spin_lock_bh(&moxa_lock);
+       spin_lock_irq(&port->lock);
        dcd = ch->DCDState;
-       spin_unlock_bh(&moxa_lock);
+       spin_unlock_irq(&port->lock);
        return dcd;
 }
 
-static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp,
-                           struct moxa_port *ch)
+static void moxa_dtr_rts(struct tty_port *port, int onoff)
 {
-       struct tty_port *port = &ch->port;
-       DEFINE_WAIT(wait);
-       int retval = 0;
-       u8 dcd;
-
-       while (1) {
-               prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE);
-               if (tty_hung_up_p(filp)) {
-#ifdef SERIAL_DO_RESTART
-                       retval = -ERESTARTSYS;
-#else
-                       retval = -EAGAIN;
-#endif
-                       break;
-               }
-               dcd = tty_port_carrier_raised(port);
-               if (dcd)
-                       break;
-
-               if (signal_pending(current)) {
-                       retval = -ERESTARTSYS;
-                       break;
-               }
-               schedule();
-       }
-       finish_wait(&port->open_wait, &wait);
-
-       return retval;
+       struct moxa_port *ch = container_of(port, struct moxa_port, port);
+       MoxaPortLineCtrl(ch, onoff, onoff);
 }
 
+
 static int moxa_open(struct tty_struct *tty, struct file *filp)
 {
        struct moxa_board_conf *brd;
@@ -1194,6 +1179,7 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
        ch->port.count++;
        tty->driver_data = ch;
        tty_port_tty_set(&ch->port, tty);
+       mutex_lock(&ch->port.mutex);
        if (!(ch->port.flags & ASYNC_INITIALIZED)) {
                ch->statusflags = 0;
                moxa_set_tty_param(tty, tty->termios);
@@ -1202,58 +1188,20 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
                MoxaSetFifo(ch, ch->type == PORT_16550A);
                ch->port.flags |= ASYNC_INITIALIZED;
        }
+       mutex_unlock(&ch->port.mutex);
        mutex_unlock(&moxa_openlock);
 
-       retval = 0;
-       if (!(filp->f_flags & O_NONBLOCK) && !C_CLOCAL(tty))
-               retval = moxa_block_till_ready(tty, filp, ch);
-       mutex_lock(&moxa_openlock);
-       if (retval) {
-               if (ch->port.count) /* 0 means already hung up... */
-                       if (--ch->port.count == 0)
-                               moxa_close_port(tty);
-       } else
-               ch->port.flags |= ASYNC_NORMAL_ACTIVE;
-       mutex_unlock(&moxa_openlock);
-
+       retval = tty_port_block_til_ready(&ch->port, tty, filp);
+       if (retval == 0)
+               set_bit(ASYNCB_NORMAL_ACTIVE, &ch->port.flags);
        return retval;
 }
 
 static void moxa_close(struct tty_struct *tty, struct file *filp)
 {
-       struct moxa_port *ch;
-       int port;
-
-       port = tty->index;
-       if (port == MAX_PORTS || tty_hung_up_p(filp))
-               return;
-
-       mutex_lock(&moxa_openlock);
-       ch = tty->driver_data;
-       if (ch == NULL)
-               goto unlock;
-       if (tty->count == 1 && ch->port.count != 1) {
-               printk(KERN_WARNING "moxa_close: bad serial port count; "
-                       "tty->count is 1, ch->port.count is %d\n", ch->port.count);
-               ch->port.count = 1;
-       }
-       if (--ch->port.count < 0) {
-               printk(KERN_WARNING "moxa_close: bad serial port count, "
-                       "device=%s\n", tty->name);
-               ch->port.count = 0;
-       }
-       if (ch->port.count)
-               goto unlock;
-
+       struct moxa_port *ch = tty->driver_data;
        ch->cflag = tty->termios->c_cflag;
-       if (ch->port.flags & ASYNC_INITIALIZED) {
-               moxa_setup_empty_event(tty);
-               tty_wait_until_sent(tty, 30 * HZ);      /* 30 seconds timeout */
-       }
-
-       moxa_close_port(tty);
-unlock:
-       mutex_unlock(&moxa_openlock);
+       tty_port_close(&ch->port, tty, filp);
 }
 
 static int moxa_write(struct tty_struct *tty,
@@ -1269,7 +1217,7 @@ static int moxa_write(struct tty_struct *tty,
        len = MoxaPortWriteData(tty, buf, count);
        spin_unlock_bh(&moxa_lock);
 
-       ch->statusflags |= LOWWAIT;
+       set_bit(LOWWAIT, &ch->statusflags);
        return len;
 }
 
@@ -1300,40 +1248,21 @@ static int moxa_chars_in_buffer(struct tty_struct *tty)
        struct moxa_port *ch = tty->driver_data;
        int chars;
 
-       /*
-        * Sigh...I have to check if driver_data is NULL here, because
-        * if an open() fails, the TTY subsystem eventually calls
-        * tty_wait_until_sent(), which calls the driver's chars_in_buffer()
-        * routine.  And since the open() failed, we return 0 here.  TDJ
-        */
-       if (ch == NULL)
-               return 0;
-       lock_kernel();
        chars = MoxaPortTxQueue(ch);
-       if (chars) {
+       if (chars)
                /*
                 * Make it possible to wakeup anything waiting for output
                 * in tty_ioctl.c, etc.
                 */
-               if (!(ch->statusflags & EMPTYWAIT))
-                       moxa_setup_empty_event(tty);
-       }
-       unlock_kernel();
+               set_bit(EMPTYWAIT, &ch->statusflags);
        return chars;
 }
 
 static int moxa_tiocmget(struct tty_struct *tty, struct file *file)
 {
-       struct moxa_port *ch;
+       struct moxa_port *ch = tty->driver_data;
        int flag = 0, dtr, rts;
 
-       mutex_lock(&moxa_openlock);
-       ch = tty->driver_data;
-       if (!ch) {
-               mutex_unlock(&moxa_openlock);
-               return -EINVAL;
-       }
-
        MoxaPortGetLineOut(ch, &dtr, &rts);
        if (dtr)
                flag |= TIOCM_DTR;
@@ -1346,7 +1275,6 @@ static int moxa_tiocmget(struct tty_struct *tty, struct file *file)
                flag |= TIOCM_DSR;
        if (dtr & 4)
                flag |= TIOCM_CD;
-       mutex_unlock(&moxa_openlock);
        return flag;
 }
 
@@ -1379,20 +1307,6 @@ static int moxa_tiocmset(struct tty_struct *tty, struct file *file,
        return 0;
 }
 
-static void moxa_throttle(struct tty_struct *tty)
-{
-       struct moxa_port *ch = tty->driver_data;
-
-       ch->statusflags |= THROTTLE;
-}
-
-static void moxa_unthrottle(struct tty_struct *tty)
-{
-       struct moxa_port *ch = tty->driver_data;
-
-       ch->statusflags &= ~THROTTLE;
-}
-
 static void moxa_set_termios(struct tty_struct *tty,
                struct ktermios *old_termios)
 {
@@ -1412,7 +1326,7 @@ static void moxa_stop(struct tty_struct *tty)
        if (ch == NULL)
                return;
        MoxaPortTxDisable(ch);
-       ch->statusflags |= TXSTOPPED;
+       set_bit(TXSTOPPED, &ch->statusflags);
 }
 
 
@@ -1427,38 +1341,32 @@ static void moxa_start(struct tty_struct *tty)
                return;
 
        MoxaPortTxEnable(ch);
-       ch->statusflags &= ~TXSTOPPED;
+       clear_bit(TXSTOPPED, &ch->statusflags);
 }
 
 static void moxa_hangup(struct tty_struct *tty)
 {
-       struct moxa_port *ch;
-
-       mutex_lock(&moxa_openlock);
-       ch = tty->driver_data;
-       if (ch == NULL) {
-               mutex_unlock(&moxa_openlock);
-               return;
-       }
-       ch->port.count = 0;
-       moxa_close_port(tty);
-       mutex_unlock(&moxa_openlock);
-
-       wake_up_interruptible(&ch->port.open_wait);
+       struct moxa_port *ch = tty->driver_data;
+       tty_port_hangup(&ch->port);
 }
 
 static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd)
 {
        struct tty_struct *tty;
+       unsigned long flags;
        dcd = !!dcd;
 
+       spin_lock_irqsave(&p->port.lock, flags);
        if (dcd != p->DCDState) {
+               p->DCDState = dcd;
+               spin_unlock_irqrestore(&p->port.lock, flags);
                tty = tty_port_tty_get(&p->port);
                if (tty && C_CLOCAL(tty) && !dcd)
                        tty_hangup(tty);
                tty_kref_put(tty);
        }
-       p->DCDState = dcd;
+       else
+               spin_unlock_irqrestore(&p->port.lock, flags);
 }
 
 static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
@@ -1470,24 +1378,24 @@ static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
        u16 intr;
 
        if (tty) {
-               if ((p->statusflags & EMPTYWAIT) &&
+               if (test_bit(EMPTYWAIT, &p->statusflags) &&
                                MoxaPortTxQueue(p) == 0) {
-                       p->statusflags &= ~EMPTYWAIT;
+                       clear_bit(EMPTYWAIT, &p->statusflags);
                        tty_wakeup(tty);
                }
-               if ((p->statusflags & LOWWAIT) && !tty->stopped &&
+               if (test_bit(LOWWAIT, &p->statusflags) && !tty->stopped &&
                                MoxaPortTxQueue(p) <= WAKEUP_CHARS) {
-                       p->statusflags &= ~LOWWAIT;
+                       clear_bit(LOWWAIT, &p->statusflags);
                        tty_wakeup(tty);
                }
 
-               if (inited && !(p->statusflags & THROTTLE) &&
+               if (inited && !test_bit(TTY_THROTTLED, &tty->flags) &&
                                MoxaPortRxQueue(p) > 0) { /* RX */
                        MoxaPortReadData(p);
                        tty_schedule_flip(tty);
                }
        } else {
-               p->statusflags &= ~EMPTYWAIT;
+               clear_bit(EMPTYWAIT, &p->statusflags);
                MoxaPortFlushData(p, 0); /* flush RX */
        }
 
@@ -1588,35 +1496,6 @@ static void moxa_set_tty_param(struct tty_struct *tty, struct ktermios *old_term
        tty_encode_baud_rate(tty, baud, baud);
 }
 
-static void moxa_setup_empty_event(struct tty_struct *tty)
-{
-       struct moxa_port *ch = tty->driver_data;
-
-       spin_lock_bh(&moxa_lock);
-       ch->statusflags |= EMPTYWAIT;
-       spin_unlock_bh(&moxa_lock);
-}
-
-static void moxa_shut_down(struct tty_struct *tty)
-{
-       struct moxa_port *ch = tty->driver_data;
-
-       if (!(ch->port.flags & ASYNC_INITIALIZED))
-               return;
-
-       MoxaPortDisable(ch);
-
-       /*
-        * If we're a modem control device and HUPCL is on, drop RTS & DTR.
-        */
-       if (C_HUPCL(tty))
-               MoxaPortLineCtrl(ch, 0, 0);
-
-       spin_lock_bh(&moxa_lock);
-       ch->port.flags &= ~ASYNC_INITIALIZED;
-       spin_unlock_bh(&moxa_lock);
-}
-
 /*****************************************************************************
  *     Driver level functions:                                              *
  *****************************************************************************/
@@ -1918,10 +1797,12 @@ static int MoxaPortSetTermio(struct moxa_port *port, struct ktermios *termio,
        baud = MoxaPortSetBaud(port, baud);
 
        if (termio->c_iflag & (IXON | IXOFF | IXANY)) {
+               spin_lock_irq(&moxafunc_lock);
                writeb(termio->c_cc[VSTART], ofsAddr + FuncArg);
                writeb(termio->c_cc[VSTOP], ofsAddr + FuncArg1);
                writeb(FC_SetXonXoff, ofsAddr + FuncCode);
                moxa_wait_finish(ofsAddr);
+               spin_unlock_irq(&moxafunc_lock);
 
        }
        return baud;
@@ -1974,18 +1855,14 @@ static int MoxaPortLineStatus(struct moxa_port *port)
        int val;
 
        ofsAddr = port->tableAddr;
-       if (MOXA_IS_320(port->board)) {
-               moxafunc(ofsAddr, FC_LineStatus, 0);
-               val = readw(ofsAddr + FuncArg);
-       } else {
+       if (MOXA_IS_320(port->board))
+               val = moxafuncret(ofsAddr, FC_LineStatus, 0);
+       else
                val = readw(ofsAddr + FlagStat) >> 4;
-       }
        val &= 0x0B;
        if (val & 8)
                val |= 4;
-       spin_lock_bh(&moxa_lock);
        moxa_new_dcdstate(port, val & 8);
-       spin_unlock_bh(&moxa_lock);
        val &= 7;
        return val;
 }
index 5e28d39b9e8196e306fabc6df4eb1ce58e6c9f70..3d923065d9a29ca1381023d132759bcb4b735ed2 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/errno.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
-#include <linux/smp_lock.h>
 #include <linux/timer.h>
 #include <linux/interrupt.h>
 #include <linux/tty.h>
@@ -856,9 +855,9 @@ static void mxser_check_modem_status(struct tty_struct *tty,
        }
 }
 
-static int mxser_startup(struct tty_struct *tty)
+static int mxser_activate(struct tty_port *port, struct tty_struct *tty)
 {
-       struct mxser_port *info = tty->driver_data;
+       struct mxser_port *info = container_of(port, struct mxser_port, port);
        unsigned long page;
        unsigned long flags;
 
@@ -868,22 +867,13 @@ static int mxser_startup(struct tty_struct *tty)
 
        spin_lock_irqsave(&info->slock, flags);
 
-       if (info->port.flags & ASYNC_INITIALIZED) {
-               free_page(page);
-               spin_unlock_irqrestore(&info->slock, flags);
-               return 0;
-       }
-
        if (!info->ioaddr || !info->type) {
                set_bit(TTY_IO_ERROR, &tty->flags);
                free_page(page);
                spin_unlock_irqrestore(&info->slock, flags);
                return 0;
        }
-       if (info->port.xmit_buf)
-               free_page(page);
-       else
-               info->port.xmit_buf = (unsigned char *) page;
+       info->port.xmit_buf = (unsigned char *) page;
 
        /*
         * Clear the FIFO buffers and disable them
@@ -951,24 +941,19 @@ static int mxser_startup(struct tty_struct *tty)
         * and set the speed of the serial port
         */
        mxser_change_speed(tty, NULL);
-       info->port.flags |= ASYNC_INITIALIZED;
        spin_unlock_irqrestore(&info->slock, flags);
 
        return 0;
 }
 
 /*
- * This routine will shutdown a serial port; interrupts maybe disabled, and
- * DTR is dropped if the hangup on close termio flag is on.
+ * This routine will shutdown a serial port
  */
-static void mxser_shutdown(struct tty_struct *tty)
+static void mxser_shutdown_port(struct tty_port *port)
 {
-       struct mxser_port *info = tty->driver_data;
+       struct mxser_port *info = container_of(port, struct mxser_port, port);
        unsigned long flags;
 
-       if (!(info->port.flags & ASYNC_INITIALIZED))
-               return;
-
        spin_lock_irqsave(&info->slock, flags);
 
        /*
@@ -978,7 +963,7 @@ static void mxser_shutdown(struct tty_struct *tty)
        wake_up_interruptible(&info->port.delta_msr_wait);
 
        /*
-        * Free the IRQ, if necessary
+        * Free the xmit buffer, if necessary
         */
        if (info->port.xmit_buf) {
                free_page((unsigned long) info->port.xmit_buf);
@@ -988,10 +973,6 @@ static void mxser_shutdown(struct tty_struct *tty)
        info->IER = 0;
        outb(0x00, info->ioaddr + UART_IER);
 
-       if (tty->termios->c_cflag & HUPCL)
-               info->MCR &= ~(UART_MCR_DTR | UART_MCR_RTS);
-       outb(info->MCR, info->ioaddr + UART_MCR);
-
        /* clear Rx/Tx FIFO's */
        if (info->board->chip_flag)
                outb(UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT |
@@ -1004,9 +985,6 @@ static void mxser_shutdown(struct tty_struct *tty)
        /* read data port to reset things */
        (void) inb(info->ioaddr + UART_RX);
 
-       set_bit(TTY_IO_ERROR, &tty->flags);
-
-       info->port.flags &= ~ASYNC_INITIALIZED;
 
        if (info->board->chip_flag)
                SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(info->ioaddr);
@@ -1023,8 +1001,7 @@ static void mxser_shutdown(struct tty_struct *tty)
 static int mxser_open(struct tty_struct *tty, struct file *filp)
 {
        struct mxser_port *info;
-       unsigned long flags;
-       int retval, line;
+       int line;
 
        line = tty->index;
        if (line == MXSER_PORTS)
@@ -1035,23 +1012,7 @@ static int mxser_open(struct tty_struct *tty, struct file *filp)
        if (!info->ioaddr)
                return -ENODEV;
 
-       tty->driver_data = info;
-       tty_port_tty_set(&info->port, tty);
-       /*
-        * Start up serial port
-        */
-       spin_lock_irqsave(&info->port.lock, flags);
-       info->port.count++;
-       spin_unlock_irqrestore(&info->port.lock, flags);
-       retval = mxser_startup(tty);
-       if (retval)
-               return retval;
-
-       retval = tty_port_block_til_ready(&info->port, tty, filp);
-       if (retval)
-               return retval;
-
-       return 0;
+       return tty_port_open(&info->port, tty, filp);
 }
 
 static void mxser_flush_buffer(struct tty_struct *tty)
@@ -1075,18 +1036,10 @@ static void mxser_flush_buffer(struct tty_struct *tty)
 }
 
 
-static void mxser_close_port(struct tty_struct *tty, struct tty_port *port)
+static void mxser_close_port(struct tty_port *port)
 {
        struct mxser_port *info = container_of(port, struct mxser_port, port);
        unsigned long timeout;
-       /*
-        * Save the termios structure, since this port may have
-        * separate termios for callout and dialin.
-        *
-        * FIXME: Can this go ?
-        */
-       if (port->flags & ASYNC_NORMAL_ACTIVE)
-               info->normal_termios = *tty->termios;
        /*
         * At this point we stop accepting input.  To do this, we
         * disable the receive line status interrupts, and tell the
@@ -1097,22 +1050,18 @@ static void mxser_close_port(struct tty_struct *tty, struct tty_port *port)
        if (info->board->chip_flag)
                info->IER &= ~MOXA_MUST_RECV_ISR;
 
-       if (port->flags & ASYNC_INITIALIZED) {
-               outb(info->IER, info->ioaddr + UART_IER);
-               /*
-                * Before we drop DTR, make sure the UART transmitter
-                * has completely drained; this is especially
-                * important if there is a transmit FIFO!
-                */
-               timeout = jiffies + HZ;
-               while (!(inb(info->ioaddr + UART_LSR) & UART_LSR_TEMT)) {
-                       schedule_timeout_interruptible(5);
-                       if (time_after(jiffies, timeout))
-                               break;
-               }
+       outb(info->IER, info->ioaddr + UART_IER);
+       /*
+        * Before we drop DTR, make sure the UART transmitter
+        * has completely drained; this is especially
+        * important if there is a transmit FIFO!
+        */
+       timeout = jiffies + HZ;
+       while (!(inb(info->ioaddr + UART_LSR) & UART_LSR_TEMT)) {
+               schedule_timeout_interruptible(5);
+               if (time_after(jiffies, timeout))
+                       break;
        }
-       mxser_shutdown(tty);
-
 }
 
 /*
@@ -1130,8 +1079,12 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
                return;
        if (tty_port_close_start(port, tty, filp) == 0)
                return;
-       mxser_close_port(tty, port);
+       mutex_lock(&port->mutex);
+       mxser_close_port(port);
        mxser_flush_buffer(tty);
+       mxser_shutdown_port(port);
+       clear_bit(ASYNCB_INITIALIZED, &port->flags);
+       mutex_unlock(&port->mutex);
        /* Right now the tty_port set is done outside of the close_end helper
           as we don't yet have everyone using refcounts */     
        tty_port_close_end(port, tty);
@@ -1275,6 +1228,7 @@ static int mxser_set_serial_info(struct tty_struct *tty,
                struct serial_struct __user *new_info)
 {
        struct mxser_port *info = tty->driver_data;
+       struct tty_port *port = &info->port;
        struct serial_struct new_serial;
        speed_t baud;
        unsigned long sl_flags;
@@ -1290,7 +1244,7 @@ static int mxser_set_serial_info(struct tty_struct *tty,
                        new_serial.port != info->ioaddr)
                return -EINVAL;
 
-       flags = info->port.flags & ASYNC_SPD_MASK;
+       flags = port->flags & ASYNC_SPD_MASK;
 
        if (!capable(CAP_SYS_ADMIN)) {
                if ((new_serial.baud_base != info->baud_base) ||
@@ -1304,16 +1258,17 @@ static int mxser_set_serial_info(struct tty_struct *tty,
                 * OK, past this point, all the error checking has been done.
                 * At this point, we start making changes.....
                 */
-               info->port.flags = ((info->port.flags & ~ASYNC_FLAGS) |
+               port->flags = ((port->flags & ~ASYNC_FLAGS) |
                                (new_serial.flags & ASYNC_FLAGS));
-               info->port.close_delay = new_serial.close_delay * HZ / 100;
-               info->port.closing_wait = new_serial.closing_wait * HZ / 100;
-               tty->low_latency = (info->port.flags & ASYNC_LOW_LATENCY)
-                                                               ? 1 : 0;
-               if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST &&
+               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;
+               if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST &&
                                (new_serial.baud_base != info->baud_base ||
                                new_serial.custom_divisor !=
                                info->custom_divisor)) {
+                       if (new_serial.custom_divisor == 0)
+                               return -EINVAL;
                        baud = new_serial.baud_base / new_serial.custom_divisor;
                        tty_encode_baud_rate(tty, baud, baud);
                }
@@ -1323,15 +1278,17 @@ static int mxser_set_serial_info(struct tty_struct *tty,
 
        process_txrx_fifo(info);
 
-       if (info->port.flags & ASYNC_INITIALIZED) {
-               if (flags != (info->port.flags & ASYNC_SPD_MASK)) {
+       if (test_bit(ASYNCB_INITIALIZED, &port->flags)) {
+               if (flags != (port->flags & ASYNC_SPD_MASK)) {
                        spin_lock_irqsave(&info->slock, sl_flags);
                        mxser_change_speed(tty, NULL);
                        spin_unlock_irqrestore(&info->slock, sl_flags);
                }
-       } else
-               retval = mxser_startup(tty);
-
+       } else {
+               retval = mxser_activate(port, tty);
+               if (retval == 0)
+                       set_bit(ASYNCB_INITIALIZED, &port->flags);
+       }
        return retval;
 }
 
@@ -1520,7 +1477,8 @@ static int __init mxser_read_register(int port, unsigned short *regs)
 
 static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
 {
-       struct mxser_port *port;
+       struct mxser_port *ip;
+       struct tty_port *port;
        struct tty_struct *tty;
        int result, status;
        unsigned int i, j;
@@ -1536,38 +1494,39 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
 
        case MOXA_CHKPORTENABLE:
                result = 0;
-               lock_kernel();
                for (i = 0; i < MXSER_BOARDS; i++)
                        for (j = 0; j < MXSER_PORTS_PER_BOARD; j++)
                                if (mxser_boards[i].ports[j].ioaddr)
                                        result |= (1 << i);
-               unlock_kernel();
                return put_user(result, (unsigned long __user *)argp);
        case MOXA_GETDATACOUNT:
-               lock_kernel();
+               /* The receive side is locked by port->slock but it isn't
+                  clear that an exact snapshot is worth copying here */
                if (copy_to_user(argp, &mxvar_log, sizeof(mxvar_log)))
                        ret = -EFAULT;
-               unlock_kernel();
                return ret;
        case MOXA_GETMSTATUS: {
                struct mxser_mstatus ms, __user *msu = argp;
-               lock_kernel();
                for (i = 0; i < MXSER_BOARDS; i++)
                        for (j = 0; j < MXSER_PORTS_PER_BOARD; j++) {
-                               port = &mxser_boards[i].ports[j];
+                               ip = &mxser_boards[i].ports[j];
+                               port = &ip->port;
                                memset(&ms, 0, sizeof(ms));
 
-                               if (!port->ioaddr)
+                               mutex_lock(&port->mutex);
+                               if (!ip->ioaddr)
                                        goto copy;
                                
-                               tty = tty_port_tty_get(&port->port);
+                               tty = tty_port_tty_get(port);
 
                                if (!tty || !tty->termios)
-                                       ms.cflag = port->normal_termios.c_cflag;
+                                       ms.cflag = ip->normal_termios.c_cflag;
                                else
                                        ms.cflag = tty->termios->c_cflag;
                                tty_kref_put(tty);
-                               status = inb(port->ioaddr + UART_MSR);
+                               spin_lock_irq(&ip->slock);
+                               status = inb(ip->ioaddr + UART_MSR);
+                               spin_unlock_irq(&ip->slock);
                                if (status & UART_MSR_DCD)
                                        ms.dcd = 1;
                                if (status & UART_MSR_DSR)
@@ -1575,13 +1534,11 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
                                if (status & UART_MSR_CTS)
                                        ms.cts = 1;
                        copy:
-                               if (copy_to_user(msu, &ms, sizeof(ms))) {
-                                       unlock_kernel();
+                               mutex_unlock(&port->mutex);
+                               if (copy_to_user(msu, &ms, sizeof(ms)))
                                        return -EFAULT;
-                               }
                                msu++;
                        }
-               unlock_kernel();
                return 0;
        }
        case MOXA_ASPP_MON_EXT: {
@@ -1593,41 +1550,48 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
                if (!me)
                        return -ENOMEM;
 
-               lock_kernel();
                for (i = 0, p = 0; i < MXSER_BOARDS; i++) {
                        for (j = 0; j < MXSER_PORTS_PER_BOARD; j++, p++) {
                                if (p >= ARRAY_SIZE(me->rx_cnt)) {
                                        i = MXSER_BOARDS;
                                        break;
                                }
-                               port = &mxser_boards[i].ports[j];
-                               if (!port->ioaddr)
+                               ip = &mxser_boards[i].ports[j];
+                               port = &ip->port;
+
+                               mutex_lock(&port->mutex);
+                               if (!ip->ioaddr) {
+                                       mutex_unlock(&port->mutex);
                                        continue;
+                               }
 
-                               status = mxser_get_msr(port->ioaddr, 0, p);
+                               spin_lock_irq(&ip->slock);
+                               status = mxser_get_msr(ip->ioaddr, 0, p);
 
                                if (status & UART_MSR_TERI)
-                                       port->icount.rng++;
+                                       ip->icount.rng++;
                                if (status & UART_MSR_DDSR)
-                                       port->icount.dsr++;
+                                       ip->icount.dsr++;
                                if (status & UART_MSR_DDCD)
-                                       port->icount.dcd++;
+                                       ip->icount.dcd++;
                                if (status & UART_MSR_DCTS)
-                                       port->icount.cts++;
+                                       ip->icount.cts++;
 
-                               port->mon_data.modem_status = status;
-                               me->rx_cnt[p] = port->mon_data.rxcnt;
-                               me->tx_cnt[p] = port->mon_data.txcnt;
-                               me->up_rxcnt[p] = port->mon_data.up_rxcnt;
-                               me->up_txcnt[p] = port->mon_data.up_txcnt;
+                               ip->mon_data.modem_status = status;
+                               me->rx_cnt[p] = ip->mon_data.rxcnt;
+                               me->tx_cnt[p] = ip->mon_data.txcnt;
+                               me->up_rxcnt[p] = ip->mon_data.up_rxcnt;
+                               me->up_txcnt[p] = ip->mon_data.up_txcnt;
                                me->modem_status[p] =
-                                       port->mon_data.modem_status;
-                               tty = tty_port_tty_get(&port->port);
+                                       ip->mon_data.modem_status;
+                               spin_unlock_irq(&ip->slock);
+
+                               tty = tty_port_tty_get(&ip->port);
 
                                if (!tty || !tty->termios) {
-                                       cflag = port->normal_termios.c_cflag;
-                                       iflag = port->normal_termios.c_iflag;
-                                       me->baudrate[p] = tty_termios_baud_rate(&port->normal_termios);
+                                       cflag = ip->normal_termios.c_cflag;
+                                       iflag = ip->normal_termios.c_iflag;
+                                       me->baudrate[p] = tty_termios_baud_rate(&ip->normal_termios);
                                } else {
                                        cflag = tty->termios->c_cflag;
                                        iflag = tty->termios->c_iflag;
@@ -1646,16 +1610,15 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
                                if (iflag & (IXON | IXOFF))
                                        me->flowctrl[p] |= 0x0C;
 
-                               if (port->type == PORT_16550A)
+                               if (ip->type == PORT_16550A)
                                        me->fifo[p] = 1;
 
-                               opmode = inb(port->opmode_ioaddr) >>
-                                               ((p % 4) * 2);
+                               opmode = inb(ip->opmode_ioaddr)>>((p % 4) * 2);
                                opmode &= OP_MODE_MASK;
                                me->iftype[p] = opmode;
+                               mutex_unlock(&port->mutex);
                        }
                }
-               unlock_kernel();
                if (copy_to_user(argp, me, sizeof(*me)))
                        ret = -EFAULT;
                kfree(me);
@@ -1692,6 +1655,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
                unsigned int cmd, unsigned long arg)
 {
        struct mxser_port *info = tty->driver_data;
+       struct tty_port *port = &info->port;
        struct async_icount cnow;
        unsigned long flags;
        void __user *argp = (void __user *)arg;
@@ -1716,20 +1680,20 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
                                        opmode != RS422_MODE &&
                                        opmode != RS485_4WIRE_MODE)
                                return -EFAULT;
-                       lock_kernel();
                        mask = ModeMask[p];
                        shiftbit = p * 2;
+                       spin_lock_irq(&info->slock);
                        val = inb(info->opmode_ioaddr);
                        val &= mask;
                        val |= (opmode << shiftbit);
                        outb(val, info->opmode_ioaddr);
-                       unlock_kernel();
+                       spin_unlock_irq(&info->slock);
                } else {
-                       lock_kernel();
                        shiftbit = p * 2;
+                       spin_lock_irq(&info->slock);
                        opmode = inb(info->opmode_ioaddr) >> shiftbit;
+                       spin_unlock_irq(&info->slock);
                        opmode &= OP_MODE_MASK;
-                       unlock_kernel();
                        if (put_user(opmode, (int __user *)argp))
                                return -EFAULT;
                }
@@ -1742,14 +1706,14 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
 
        switch (cmd) {
        case TIOCGSERIAL:
-               lock_kernel();
+               mutex_lock(&port->mutex);
                retval = mxser_get_serial_info(tty, argp);
-               unlock_kernel();
+               mutex_unlock(&port->mutex);
                return retval;
        case TIOCSSERIAL:
-               lock_kernel();
+               mutex_lock(&port->mutex);
                retval = mxser_set_serial_info(tty, argp);
-               unlock_kernel();
+               mutex_unlock(&port->mutex);
                return retval;
        case TIOCSERGETLSR:     /* Get line status register */
                return  mxser_get_lsr_info(info, argp);
@@ -1795,31 +1759,33 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
        case MOXA_HighSpeedOn:
                return put_user(info->baud_base != 115200 ? 1 : 0, (int __user *)argp);
        case MOXA_SDS_RSTICOUNTER:
-               lock_kernel();
+               spin_lock_irq(&info->slock);
                info->mon_data.rxcnt = 0;
                info->mon_data.txcnt = 0;
-               unlock_kernel();
+               spin_unlock_irq(&info->slock);
                return 0;
 
        case MOXA_ASPP_OQUEUE:{
                int len, lsr;
 
-               lock_kernel();
                len = mxser_chars_in_buffer(tty);
+               spin_lock(&info->slock);
                lsr = inb(info->ioaddr + UART_LSR) & UART_LSR_THRE;
+               spin_unlock_irq(&info->slock);
                len += (lsr ? 0 : 1);
-               unlock_kernel();
 
                return put_user(len, (int __user *)argp);
        }
        case MOXA_ASPP_MON: {
                int mcr, status;
 
-               lock_kernel();
+               spin_lock(&info->slock);
                status = mxser_get_msr(info->ioaddr, 1, tty->index);
                mxser_check_modem_status(tty, info, status);
 
                mcr = inb(info->ioaddr + UART_MCR);
+               spin_unlock(&info->slock);
+
                if (mcr & MOXA_MUST_MCR_XON_FLAG)
                        info->mon_data.hold_reason &= ~NPPI_NOTIFY_XOFFHOLD;
                else
@@ -1834,7 +1800,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
                        info->mon_data.hold_reason |= NPPI_NOTIFY_CTSHOLD;
                else
                        info->mon_data.hold_reason &= ~NPPI_NOTIFY_CTSHOLD;
-               unlock_kernel();
+
                if (copy_to_user(argp, &info->mon_data,
                                sizeof(struct mxser_mon)))
                        return -EFAULT;
@@ -1993,6 +1959,7 @@ static void mxser_wait_until_sent(struct tty_struct *tty, int timeout)
 {
        struct mxser_port *info = tty->driver_data;
        unsigned long orig_jiffies, char_time;
+       unsigned long flags;
        int lsr;
 
        if (info->type == PORT_UNKNOWN)
@@ -2032,19 +1999,21 @@ static void mxser_wait_until_sent(struct tty_struct *tty, int timeout)
                timeout, char_time);
        printk("jiff=%lu...", jiffies);
 #endif
-       lock_kernel();
+       spin_lock_irqsave(&info->slock, flags);
        while (!((lsr = inb(info->ioaddr + UART_LSR)) & UART_LSR_TEMT)) {
 #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
                printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
 #endif
+               spin_unlock_irqrestore(&info->slock, flags);
                schedule_timeout_interruptible(char_time);
+               spin_lock_irqsave(&info->slock, flags);
                if (signal_pending(current))
                        break;
                if (timeout && time_after(jiffies, orig_jiffies + timeout))
                        break;
        }
+       spin_unlock_irqrestore(&info->slock, flags);
        set_current_state(TASK_RUNNING);
-       unlock_kernel();
 
 #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
        printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
@@ -2059,7 +2028,6 @@ static void mxser_hangup(struct tty_struct *tty)
        struct mxser_port *info = tty->driver_data;
 
        mxser_flush_buffer(tty);
-       mxser_shutdown(tty);
        tty_port_hangup(&info->port);
 }
 
@@ -2363,6 +2331,8 @@ static const struct tty_operations mxser_ops = {
 struct tty_port_operations mxser_port_ops = {
        .carrier_raised = mxser_carrier_raised,
        .dtr_rts = mxser_dtr_rts,
+       .activate = mxser_activate,
+       .shutdown = mxser_shutdown_port,
 };
 
 /*
index 674b3ab3587d505458fbdb802fc0a7cbcdf7d2eb..2bb7874a6899d5afee7e1bc65c154f63ee482287 100644 (file)
@@ -603,7 +603,7 @@ void ipwireless_tty_free(struct ipw_tty *tty)
        }
 }
 
-static struct tty_operations tty_ops = {
+static const struct tty_operations tty_ops = {
        .open = ipw_open,
        .close = ipw_close,
        .hangup = ipw_hangup,
index d86c0bc05c1c7839b4db8873daf96a21fd32cfe8..385c44b3034f4000df9d8a4ad917f3e030c4a143 100644 (file)
@@ -659,7 +659,7 @@ static int __ptmx_open(struct inode *inode, struct file *filp)
        if (!retval)
                return 0;
 out1:
-       tty_release_dev(filp);
+       tty_release(inode, filp);
        return retval;
 out:
        devpts_kill_index(inode, index);
index 3cfa22d469e0cd7f74e01b416f428dc3be508add..0a8d1e56c99362e0da9b1df06c2452d30341d006 100644 (file)
@@ -793,26 +793,21 @@ static void rc_change_speed(struct tty_struct *tty, struct riscom_board *bp,
 }
 
 /* Must be called with interrupts enabled */
-static int rc_setup_port(struct tty_struct *tty, struct riscom_board *bp,
-                                               struct riscom_port *port)
+static int rc_activate_port(struct tty_port *port, struct tty_struct *tty)
 {
+       struct riscom_port *rp = container_of(port, struct riscom_port, port);
+       struct riscom_board *bp = port_Board(rp);
        unsigned long flags;
 
-       if (port->port.flags & ASYNC_INITIALIZED)
-               return 0;
-
-       if (tty_port_alloc_xmit_buf(&port->port) < 0)
+       if (tty_port_alloc_xmit_buf(port) < 0)
                return -ENOMEM;
 
        spin_lock_irqsave(&riscom_lock, flags);
 
        clear_bit(TTY_IO_ERROR, &tty->flags);
-       if (port->port.count == 1)
-               bp->count++;
-       port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
-       rc_change_speed(tty, bp, port);
-       port->port.flags |= ASYNC_INITIALIZED;
-
+       bp->count++;
+       rp->xmit_cnt = rp->xmit_head = rp->xmit_tail = 0;
+       rc_change_speed(tty, bp, rp);
        spin_unlock_irqrestore(&riscom_lock, flags);
        return 0;
 }
@@ -821,9 +816,6 @@ static int rc_setup_port(struct tty_struct *tty, struct riscom_board *bp,
 static void rc_shutdown_port(struct tty_struct *tty,
                        struct riscom_board *bp, struct riscom_port *port)
 {
-       if (!(port->port.flags & ASYNC_INITIALIZED))
-               return;
-
 #ifdef RC_REPORT_OVERRUN
        printk(KERN_INFO "rc%d: port %d: Total %ld overruns were detected.\n",
               board_No(bp), port_No(port), port->overrun);
@@ -840,11 +832,6 @@ static void rc_shutdown_port(struct tty_struct *tty,
        }
 #endif
        tty_port_free_xmit_buf(&port->port);
-       if (C_HUPCL(tty)) {
-               /* Drop DTR */
-               bp->DTR |= (1u << port_No(port));
-               rc_out(bp, RC_DTR, bp->DTR);
-       }
 
        /* Select port */
        rc_out(bp, CD180_CAR, port_No(port));
@@ -856,7 +843,6 @@ static void rc_shutdown_port(struct tty_struct *tty,
        rc_out(bp, CD180_IER, port->IER);
 
        set_bit(TTY_IO_ERROR, &tty->flags);
-       port->port.flags &= ~ASYNC_INITIALIZED;
 
        if (--bp->count < 0)  {
                printk(KERN_INFO "rc%d: rc_shutdown_port: "
@@ -889,6 +875,20 @@ static int carrier_raised(struct tty_port *port)
        return CD;
 }
 
+static void dtr_rts(struct tty_port *port, int onoff)
+{
+       struct riscom_port *p = container_of(port, struct riscom_port, port);
+       struct riscom_board *bp = port_Board(p);
+       unsigned long flags;
+
+       spin_lock_irqsave(&riscom_lock, flags);
+       bp->DTR &= ~(1u << port_No(p));
+       if (onoff == 0)
+               bp->DTR |= (1u << port_No(p));
+       rc_out(bp, RC_DTR, bp->DTR);
+       spin_unlock_irqrestore(&riscom_lock, flags);
+}
+
 static int rc_open(struct tty_struct *tty, struct file *filp)
 {
        int board;
@@ -909,14 +909,7 @@ static int rc_open(struct tty_struct *tty, struct file *filp)
        if (error)
                return error;
 
-       port->port.count++;
-       tty->driver_data = port;
-       tty_port_tty_set(&port->port, tty);
-
-       error = rc_setup_port(tty, bp, port);
-       if (error == 0)
-               error = tty_port_block_til_ready(&port->port, tty, filp);
-       return error;
+       return tty_port_open(&port->port, tty, filp);
 }
 
 static void rc_flush_buffer(struct tty_struct *tty)
@@ -950,24 +943,23 @@ static void rc_close_port(struct tty_port *port)
 
        spin_lock_irqsave(&riscom_lock, flags);
        rp->IER &= ~IER_RXD;
-       if (port->flags & ASYNC_INITIALIZED) {
-               rp->IER &= ~IER_TXRDY;
-               rp->IER |= IER_TXEMPTY;
-               rc_out(bp, CD180_CAR, port_No(rp));
-               rc_out(bp, CD180_IER, rp->IER);
-               /*
-                * Before we drop DTR, make sure the UART transmitter
-                * has completely drained; this is especially
-                * important if there is a transmit FIFO!
-                */
-               timeout = jiffies + HZ;
-               while (rp->IER & IER_TXEMPTY) {
-                       spin_unlock_irqrestore(&riscom_lock, flags);
-                       msleep_interruptible(jiffies_to_msecs(rp->timeout));
-                       spin_lock_irqsave(&riscom_lock, flags);
-                       if (time_after(jiffies, timeout))
-                               break;
-               }
+
+       rp->IER &= ~IER_TXRDY;
+       rp->IER |= IER_TXEMPTY;
+       rc_out(bp, CD180_CAR, port_No(rp));
+       rc_out(bp, CD180_IER, rp->IER);
+       /*
+        * Before we drop DTR, make sure the UART transmitter
+        * has completely drained; this is especially
+        * important if there is a transmit FIFO!
+        */
+       timeout = jiffies + HZ;
+       while (rp->IER & IER_TXEMPTY) {
+               spin_unlock_irqrestore(&riscom_lock, flags);
+               msleep_interruptible(jiffies_to_msecs(rp->timeout));
+               spin_lock_irqsave(&riscom_lock, flags);
+               if (time_after(jiffies, timeout))
+                       break;
        }
        rc_shutdown_port(port->tty, bp, rp);
        spin_unlock_irqrestore(&riscom_lock, flags);
@@ -1354,7 +1346,6 @@ static void rc_hangup(struct tty_struct *tty)
        if (rc_paranoia_check(port, tty->name, "rc_hangup"))
                return;
 
-       rc_shutdown_port(tty, port_Board(port), port);
        tty_port_hangup(&port->port);
 }
 
@@ -1401,7 +1392,9 @@ static const struct tty_operations riscom_ops = {
 
 static const struct tty_port_operations riscom_port_ops = {
        .carrier_raised = carrier_raised,
+       .dtr_rts = dtr_rts,
        .shutdown = rc_close_port,
+       .activate = rc_activate_port,
 };
 
 
index db6dcfa35ba0dc44e183f33c5ded7b3a4f0e6051..0e511d61f544eac34417456e509d86bedfd13624 100644 (file)
@@ -407,7 +407,7 @@ static unsigned int stl_baudrates[] = {
  *     Declare all those functions in this driver!
  */
 
-static int     stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg);
+static long    stl_memioctl(struct file *fp, unsigned int cmd, unsigned long arg);
 static int     stl_brdinit(struct stlbrd *brdp);
 static int     stl_getportstats(struct tty_struct *tty, struct stlport *portp, comstats_t __user *cp);
 static int     stl_clrportstats(struct stlport *portp, comstats_t __user *cp);
@@ -607,7 +607,7 @@ static unsigned int sc26198_baudtable[] = {
  */
 static const struct file_operations    stl_fsiomem = {
        .owner          = THIS_MODULE,
-       .ioctl          = stl_memioctl,
+       .unlocked_ioctl = stl_memioctl,
 };
 
 static struct class *stallion_class;
@@ -702,6 +702,24 @@ static struct stlbrd *stl_allocbrd(void)
 
 /*****************************************************************************/
 
+static int stl_activate(struct tty_port *port, struct tty_struct *tty)
+{
+       struct stlport *portp = container_of(port, struct stlport, port);
+       if (!portp->tx.buf) {
+               portp->tx.buf = kmalloc(STL_TXBUFSIZE, GFP_KERNEL);
+               if (!portp->tx.buf)
+                       return -ENOMEM;
+               portp->tx.head = portp->tx.buf;
+               portp->tx.tail = portp->tx.buf;
+       }
+       stl_setport(portp, tty->termios);
+       portp->sigs = stl_getsignals(portp);
+       stl_setsignals(portp, 1, 1);
+       stl_enablerxtx(portp, 1, 1);
+       stl_startrxtx(portp, 1, 0);
+       return 0;
+}
+
 static int stl_open(struct tty_struct *tty, struct file *filp)
 {
        struct stlport  *portp;
@@ -737,32 +755,8 @@ static int stl_open(struct tty_struct *tty, struct file *filp)
        if (portp == NULL)
                return -ENODEV;
        port = &portp->port;
+       return tty_port_open(&portp->port, tty, filp);
 
-/*
- *     On the first open of the device setup the port hardware, and
- *     initialize the per port data structure.
- */
-       tty_port_tty_set(port, tty);
-       tty->driver_data = portp;
-       port->count++;
-
-       if ((port->flags & ASYNC_INITIALIZED) == 0) {
-               if (!portp->tx.buf) {
-                       portp->tx.buf = kmalloc(STL_TXBUFSIZE, GFP_KERNEL);
-                       if (!portp->tx.buf)
-                               return -ENOMEM;
-                       portp->tx.head = portp->tx.buf;
-                       portp->tx.tail = portp->tx.buf;
-               }
-               stl_setport(portp, tty->termios);
-               portp->sigs = stl_getsignals(portp);
-               stl_setsignals(portp, 1, 1);
-               stl_enablerxtx(portp, 1, 1);
-               stl_startrxtx(portp, 1, 0);
-               clear_bit(TTY_IO_ERROR, &tty->flags);
-               port->flags |= ASYNC_INITIALIZED;
-       }
-       return tty_port_block_til_ready(port, tty, filp);
 }
 
 /*****************************************************************************/
@@ -826,38 +820,12 @@ static void stl_waituntilsent(struct tty_struct *tty, int timeout)
 
 /*****************************************************************************/
 
-static void stl_close(struct tty_struct *tty, struct file *filp)
+static void stl_shutdown(struct tty_port *port)
 {
-       struct stlport  *portp;
-       struct tty_port *port;
-       unsigned long   flags;
-
-       pr_debug("stl_close(tty=%p,filp=%p)\n", tty, filp);
-
-       portp = tty->driver_data;
-       BUG_ON(portp == NULL);
-
-       port = &portp->port;
-
-       if (tty_port_close_start(port, tty, filp) == 0)
-               return;
-/*
- *     May want to wait for any data to drain before closing. The BUSY
- *     flag keeps track of whether we are still sending or not - it is
- *     very accurate for the cd1400, not quite so for the sc26198.
- *     (The sc26198 has no "end-of-data" interrupt only empty FIFO)
- */
-       stl_waituntilsent(tty, (HZ / 2));
-
-       spin_lock_irqsave(&port->lock, flags);
-       portp->port.flags &= ~ASYNC_INITIALIZED;
-       spin_unlock_irqrestore(&port->lock, flags);
-
+       struct stlport *portp = container_of(port, struct stlport, port);
        stl_disableintrs(portp);
-       if (tty->termios->c_cflag & HUPCL)
-               stl_setsignals(portp, 0, 0);
        stl_enablerxtx(portp, 0, 0);
-       stl_flushbuffer(tty);
+       stl_flush(portp);
        portp->istate = 0;
        if (portp->tx.buf != NULL) {
                kfree(portp->tx.buf);
@@ -865,9 +833,16 @@ static void stl_close(struct tty_struct *tty, struct file *filp)
                portp->tx.head = NULL;
                portp->tx.tail = NULL;
        }
+}
+
+static void stl_close(struct tty_struct *tty, struct file *filp)
+{
+       struct stlport*portp;
+       pr_debug("stl_close(tty=%p,filp=%p)\n", tty, filp);
 
-       tty_port_close_end(port, tty);
-       tty_port_tty_set(port, NULL);
+       portp = tty->driver_data;
+       BUG_ON(portp == NULL);
+       tty_port_close(&portp->port, tty, filp);
 }
 
 /*****************************************************************************/
@@ -1314,35 +1289,12 @@ static void stl_stop(struct tty_struct *tty)
 
 static void stl_hangup(struct tty_struct *tty)
 {
-       struct stlport  *portp;
-       struct tty_port *port;
-       unsigned long flags;
-
+       struct stlport  *portp = tty->driver_data;
        pr_debug("stl_hangup(tty=%p)\n", tty);
 
-       portp = tty->driver_data;
        if (portp == NULL)
                return;
-       port = &portp->port;
-
-       spin_lock_irqsave(&port->lock, flags);
-       port->flags &= ~ASYNC_INITIALIZED;
-       spin_unlock_irqrestore(&port->lock, flags);
-
-       stl_disableintrs(portp);
-       if (tty->termios->c_cflag & HUPCL)
-               stl_setsignals(portp, 0, 0);
-       stl_enablerxtx(portp, 0, 0);
-       stl_flushbuffer(tty);
-       portp->istate = 0;
-       set_bit(TTY_IO_ERROR, &tty->flags);
-       if (portp->tx.buf != NULL) {
-               kfree(portp->tx.buf);
-               portp->tx.buf = NULL;
-               portp->tx.head = NULL;
-               portp->tx.tail = NULL;
-       }
-       tty_port_hangup(port);
+       tty_port_hangup(&portp->port);
 }
 
 /*****************************************************************************/
@@ -2486,18 +2438,19 @@ static int stl_getbrdstruct(struct stlbrd __user *arg)
  *     collection.
  */
 
-static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg)
+static long stl_memioctl(struct file *fp, unsigned int cmd, unsigned long arg)
 {
        int     brdnr, rc;
        void __user *argp = (void __user *)arg;
 
-       pr_debug("stl_memioctl(ip=%p,fp=%p,cmd=%x,arg=%lx)\n", ip, fp, cmd,arg);
+       pr_debug("stl_memioctl(fp=%p,cmd=%x,arg=%lx)\n", fp, cmd,arg);
 
-       brdnr = iminor(ip);
+       brdnr = iminor(fp->f_dentry->d_inode);
        if (brdnr >= STL_MAXBRDS)
                return -ENODEV;
        rc = 0;
 
+       lock_kernel();
        switch (cmd) {
        case COM_GETPORTSTATS:
                rc = stl_getportstats(NULL, NULL, argp);
@@ -2518,7 +2471,7 @@ static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, uns
                rc = -ENOIOCTLCMD;
                break;
        }
-
+       unlock_kernel();
        return rc;
 }
 
@@ -2549,6 +2502,8 @@ static const struct tty_operations stl_ops = {
 static const struct tty_port_operations stl_port_ops = {
        .carrier_raised = stl_carrier_raised,
        .dtr_rts = stl_dtr_rts,
+       .activate = stl_activate,
+       .shutdown = stl_shutdown,
 };
 
 /*****************************************************************************/
index 59499ee0fe6a11850eb851ad829dbb1a1b0d6dbc..684f0e0b175eddb9e25fe3ff1d45b8ce12fa5fcf 100644 (file)
@@ -142,7 +142,6 @@ ssize_t redirected_tty_write(struct file *, const char __user *,
                                                        size_t, loff_t *);
 static unsigned int tty_poll(struct file *, poll_table *);
 static int tty_open(struct inode *, struct file *);
-static int tty_release(struct inode *, struct file *);
 long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
 #ifdef CONFIG_COMPAT
 static long tty_compat_ioctl(struct file *file, unsigned int cmd,
@@ -506,8 +505,6 @@ static void do_tty_hangup(struct work_struct *work)
        if (!tty)
                return;
 
-       /* inuse_filps is protected by the single kernel lock */
-       lock_kernel();
 
        spin_lock(&redirect_lock);
        if (redirect && redirect->private_data == tty) {
@@ -516,7 +513,11 @@ static void do_tty_hangup(struct work_struct *work)
        }
        spin_unlock(&redirect_lock);
 
+       /* inuse_filps is protected by the single kernel lock */
+       lock_kernel();
        check_tty_count(tty, "do_tty_hangup");
+       unlock_kernel();
+
        file_list_lock();
        /* This breaks for file handles being sent over AF_UNIX sockets ? */
        list_for_each_entry(filp, &tty->tty_files, f_u.fu_list) {
@@ -530,6 +531,7 @@ static void do_tty_hangup(struct work_struct *work)
        }
        file_list_unlock();
 
+       lock_kernel();
        tty_ldisc_hangup(tty);
 
        read_lock(&tasklist_lock);
@@ -708,6 +710,8 @@ void disassociate_ctty(int on_exit)
        struct tty_struct *tty;
        struct pid *tty_pgrp = NULL;
 
+       if (!current->signal->leader)
+               return;
 
        tty = get_current_tty();
        if (tty) {
@@ -773,8 +777,7 @@ void no_tty(void)
 {
        struct task_struct *tsk = current;
        lock_kernel();
-       if (tsk->signal->leader)
-               disassociate_ctty(0);
+       disassociate_ctty(0);
        unlock_kernel();
        proc_clear_tty(tsk);
 }
@@ -1017,14 +1020,16 @@ out:
 
 void tty_write_message(struct tty_struct *tty, char *msg)
 {
-       lock_kernel();
        if (tty) {
                mutex_lock(&tty->atomic_write_lock);
-               if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags))
+               lock_kernel();
+               if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) {
+                       unlock_kernel();
                        tty->ops->write(tty, msg, strlen(msg));
+               } else
+                       unlock_kernel();
                tty_write_unlock(tty);
        }
-       unlock_kernel();
        return;
 }
 
@@ -1202,14 +1207,21 @@ static int tty_driver_install_tty(struct tty_driver *driver,
                                                struct tty_struct *tty)
 {
        int idx = tty->index;
+       int ret;
 
-       if (driver->ops->install)
-               return driver->ops->install(driver, tty);
+       if (driver->ops->install) {
+               lock_kernel();
+               ret = driver->ops->install(driver, tty);
+               unlock_kernel();
+               return ret;
+       }
 
        if (tty_init_termios(tty) == 0) {
+               lock_kernel();
                tty_driver_kref_get(driver);
                tty->count++;
                driver->ttys[idx] = tty;
+               unlock_kernel();
                return 0;
        }
        return -ENOMEM;
@@ -1302,10 +1314,14 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
        struct tty_struct *tty;
        int retval;
 
+       lock_kernel();
        /* Check if pty master is being opened multiple times */
        if (driver->subtype == PTY_TYPE_MASTER &&
-               (driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok)
+               (driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok) {
+               unlock_kernel();
                return ERR_PTR(-EIO);
+       }
+       unlock_kernel();
 
        /*
         * First time open is complex, especially for PTY devices.
@@ -1335,7 +1351,6 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
         * If we fail here just call release_tty to clean up.  No need
         * to decrement the use counts, as release_tty doesn't care.
         */
-
        retval = tty_ldisc_setup(tty, tty->link);
        if (retval)
                goto release_mem_out;
@@ -1350,7 +1365,9 @@ release_mem_out:
        if (printk_ratelimit())
                printk(KERN_INFO "tty_init_dev: ldisc open failed, "
                                 "clearing slot %d\n", idx);
+       lock_kernel();
        release_tty(tty, idx);
+       unlock_kernel();
        return ERR_PTR(retval);
 }
 
@@ -1464,7 +1481,17 @@ static void release_tty(struct tty_struct *tty, int idx)
        tty_kref_put(tty);
 }
 
-/*
+/**
+ *     tty_release             -       vfs callback for close
+ *     @inode: inode of tty
+ *     @filp: file pointer for handle to tty
+ *
+ *     Called the last time each file handle is closed that references
+ *     this tty. There may however be several such references.
+ *
+ *     Locking:
+ *             Takes bkl. See tty_release_dev
+ *
  * Even releasing the tty structures is a tricky business.. We have
  * to be very careful that the structures are all released at the
  * same time, as interrupts might otherwise get the wrong pointers.
@@ -1472,20 +1499,20 @@ static void release_tty(struct tty_struct *tty, int idx)
  * WSH 09/09/97: rewritten to avoid some nasty race conditions that could
  * lead to double frees or releasing memory still in use.
  */
-void tty_release_dev(struct file *filp)
+
+int tty_release(struct inode *inode, struct file *filp)
 {
        struct tty_struct *tty, *o_tty;
        int     pty_master, tty_closing, o_tty_closing, do_sleep;
        int     devpts;
        int     idx;
        char    buf[64];
-       struct  inode *inode;
 
-       inode = filp->f_path.dentry->d_inode;
        tty = (struct tty_struct *)filp->private_data;
        if (tty_paranoia_check(tty, inode, "tty_release_dev"))
-               return;
+               return 0;
 
+       lock_kernel();
        check_tty_count(tty, "tty_release_dev");
 
        tty_fasync(-1, filp, 0);
@@ -1500,19 +1527,22 @@ void tty_release_dev(struct file *filp)
        if (idx < 0 || idx >= tty->driver->num) {
                printk(KERN_DEBUG "tty_release_dev: bad idx when trying to "
                                  "free (%s)\n", tty->name);
-               return;
+               unlock_kernel();
+               return 0;
        }
        if (!devpts) {
                if (tty != tty->driver->ttys[idx]) {
+                       unlock_kernel();
                        printk(KERN_DEBUG "tty_release_dev: driver.table[%d] not tty "
                               "for (%s)\n", idx, tty->name);
-                       return;
+                       return 0;
                }
                if (tty->termios != tty->driver->termios[idx]) {
+                       unlock_kernel();
                        printk(KERN_DEBUG "tty_release_dev: driver.termios[%d] not termios "
                               "for (%s)\n",
                               idx, tty->name);
-                       return;
+                       return 0;
                }
        }
 #endif
@@ -1526,26 +1556,30 @@ void tty_release_dev(struct file *filp)
        if (tty->driver->other &&
             !(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
                if (o_tty != tty->driver->other->ttys[idx]) {
+                       unlock_kernel();
                        printk(KERN_DEBUG "tty_release_dev: other->table[%d] "
                                          "not o_tty for (%s)\n",
                               idx, tty->name);
-                       return;
+                       return 0 ;
                }
                if (o_tty->termios != tty->driver->other->termios[idx]) {
+                       unlock_kernel();
                        printk(KERN_DEBUG "tty_release_dev: other->termios[%d] "
                                          "not o_termios for (%s)\n",
                               idx, tty->name);
-                       return;
+                       return 0;
                }
                if (o_tty->link != tty) {
+                       unlock_kernel();
                        printk(KERN_DEBUG "tty_release_dev: bad pty pointers\n");
-                       return;
+                       return 0;
                }
        }
 #endif
        if (tty->ops->close)
                tty->ops->close(tty, filp);
 
+       unlock_kernel();
        /*
         * Sanity check: if tty->count is going to zero, there shouldn't be
         * any waiters on tty->read_wait or tty->write_wait.  We test the
@@ -1568,6 +1602,7 @@ void tty_release_dev(struct file *filp)
                   opens on /dev/tty */
 
                mutex_lock(&tty_mutex);
+               lock_kernel();
                tty_closing = tty->count <= 1;
                o_tty_closing = o_tty &&
                        (o_tty->count <= (pty_master ? 1 : 0));
@@ -1598,6 +1633,7 @@ void tty_release_dev(struct file *filp)
 
                printk(KERN_WARNING "tty_release_dev: %s: read/write wait queue "
                                    "active!\n", tty_name(tty, buf));
+               unlock_kernel();
                mutex_unlock(&tty_mutex);
                schedule();
        }
@@ -1661,8 +1697,10 @@ void tty_release_dev(struct file *filp)
        mutex_unlock(&tty_mutex);
 
        /* check whether both sides are closing ... */
-       if (!tty_closing || (o_tty && !o_tty_closing))
-               return;
+       if (!tty_closing || (o_tty && !o_tty_closing)) {
+               unlock_kernel();
+               return 0;
+       }
 
 #ifdef TTY_DEBUG_HANGUP
        printk(KERN_DEBUG "freeing tty structure...");
@@ -1680,10 +1718,12 @@ void tty_release_dev(struct file *filp)
        /* Make this pty number available for reallocation */
        if (devpts)
                devpts_kill_index(inode, idx);
+       unlock_kernel();
+       return 0;
 }
 
 /**
- *     __tty_open              -       open a tty device
+ *     tty_open                -       open a tty device
  *     @inode: inode of device file
  *     @filp: file pointer to tty
  *
@@ -1703,7 +1743,7 @@ void tty_release_dev(struct file *filp)
  *              ->siglock protects ->signal/->sighand
  */
 
-static int __tty_open(struct inode *inode, struct file *filp)
+static int tty_open(struct inode *inode, struct file *filp)
 {
        struct tty_struct *tty = NULL;
        int noctty, retval;
@@ -1720,10 +1760,12 @@ retry_open:
        retval = 0;
 
        mutex_lock(&tty_mutex);
+       lock_kernel();
 
        if (device == MKDEV(TTYAUX_MAJOR, 0)) {
                tty = get_current_tty();
                if (!tty) {
+                       unlock_kernel();
                        mutex_unlock(&tty_mutex);
                        return -ENXIO;
                }
@@ -1755,12 +1797,14 @@ retry_open:
                                goto got_driver;
                        }
                }
+               unlock_kernel();
                mutex_unlock(&tty_mutex);
                return -ENODEV;
        }
 
        driver = get_tty_driver(device, &index);
        if (!driver) {
+               unlock_kernel();
                mutex_unlock(&tty_mutex);
                return -ENODEV;
        }
@@ -1770,6 +1814,7 @@ got_driver:
                tty = tty_driver_lookup_tty(driver, inode, index);
 
                if (IS_ERR(tty)) {
+                       unlock_kernel();
                        mutex_unlock(&tty_mutex);
                        return PTR_ERR(tty);
                }
@@ -1784,8 +1829,10 @@ got_driver:
 
        mutex_unlock(&tty_mutex);
        tty_driver_kref_put(driver);
-       if (IS_ERR(tty))
+       if (IS_ERR(tty)) {
+               unlock_kernel();
                return PTR_ERR(tty);
+       }
 
        filp->private_data = tty;
        file_move(filp, &tty->tty_files);
@@ -1813,11 +1860,15 @@ got_driver:
                printk(KERN_DEBUG "error %d in opening %s...", retval,
                       tty->name);
 #endif
-               tty_release_dev(filp);
-               if (retval != -ERESTARTSYS)
+               tty_release(inode, filp);
+               if (retval != -ERESTARTSYS) {
+                       unlock_kernel();
                        return retval;
-               if (signal_pending(current))
+               }
+               if (signal_pending(current)) {
+                       unlock_kernel();
                        return retval;
+               }
                schedule();
                /*
                 * Need to reset f_op in case a hangup happened.
@@ -1826,8 +1877,11 @@ got_driver:
                        filp->f_op = &tty_fops;
                goto retry_open;
        }
+       unlock_kernel();
+
 
        mutex_lock(&tty_mutex);
+       lock_kernel();
        spin_lock_irq(&current->sighand->siglock);
        if (!noctty &&
            current->signal->leader &&
@@ -1835,43 +1889,12 @@ got_driver:
            tty->session == NULL)
                __proc_set_tty(current, tty);
        spin_unlock_irq(&current->sighand->siglock);
+       unlock_kernel();
        mutex_unlock(&tty_mutex);
        return 0;
 }
 
-/* BKL pushdown: scary code avoidance wrapper */
-static int tty_open(struct inode *inode, struct file *filp)
-{
-       int ret;
-
-       lock_kernel();
-       ret = __tty_open(inode, filp);
-       unlock_kernel();
-       return ret;
-}
-
-
-
-
-/**
- *     tty_release             -       vfs callback for close
- *     @inode: inode of tty
- *     @filp: file pointer for handle to tty
- *
- *     Called the last time each file handle is closed that references
- *     this tty. There may however be several such references.
- *
- *     Locking:
- *             Takes bkl. See tty_release_dev
- */
 
-static int tty_release(struct inode *inode, struct file *filp)
-{
-       lock_kernel();
-       tty_release_dev(filp);
-       unlock_kernel();
-       return 0;
-}
 
 /**
  *     tty_poll        -       check tty status
@@ -2317,9 +2340,7 @@ static int tiocsetd(struct tty_struct *tty, int __user *p)
        if (get_user(ldisc, p))
                return -EFAULT;
 
-       lock_kernel();
        ret = tty_set_ldisc(tty, ldisc);
-       unlock_kernel();
 
        return ret;
 }
index feb55075819bab4f7d9f75ce11f7aa7232ba9dc1..3f653f7d849f07f256fa4ae0e0d11376d0e07825 100644 (file)
@@ -34,6 +34,8 @@
 #include <linux/vt_kern.h>
 #include <linux/selection.h>
 
+#include <linux/smp_lock.h>    /* For the moment */
+
 #include <linux/kmod.h>
 #include <linux/nsproxy.h>
 
@@ -443,8 +445,14 @@ static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
 static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld)
 {
        WARN_ON(test_and_set_bit(TTY_LDISC_OPEN, &tty->flags));
-       if (ld->ops->open)
-               return ld->ops->open(tty);
+       if (ld->ops->open) {
+               int ret;
+                /* BKL here locks verus a hangup event */
+               lock_kernel();
+               ret = ld->ops->open(tty);
+               unlock_kernel();
+               return ret;
+       }
        return 0;
 }
 
@@ -545,6 +553,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
        if (IS_ERR(new_ldisc))
                return PTR_ERR(new_ldisc);
 
+       lock_kernel();
        /*
         *      We need to look at the tty locking here for pty/tty pairs
         *      when both sides try to change in parallel.
@@ -558,10 +567,12 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
         */
 
        if (tty->ldisc->ops->num == ldisc) {
+               unlock_kernel();
                tty_ldisc_put(new_ldisc);
                return 0;
        }
 
+       unlock_kernel();
        /*
         *      Problem: What do we do if this blocks ?
         *      We could deadlock here
@@ -582,6 +593,9 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
                        test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0);
                mutex_lock(&tty->ldisc_mutex);
        }
+
+       lock_kernel();
+
        set_bit(TTY_LDISC_CHANGING, &tty->flags);
 
        /*
@@ -592,6 +606,8 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
        tty->receive_room = 0;
 
        o_ldisc = tty->ldisc;
+
+       unlock_kernel();
        /*
         *      Make sure we don't change while someone holds a
         *      reference to the line discipline. The TTY_LDISC bit
@@ -617,12 +633,14 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
        flush_scheduled_work();
 
        mutex_lock(&tty->ldisc_mutex);
+       lock_kernel();
        if (test_bit(TTY_HUPPED, &tty->flags)) {
                /* We were raced by the hangup method. It will have stomped
                   the ldisc data and closed the ldisc down */
                clear_bit(TTY_LDISC_CHANGING, &tty->flags);
                mutex_unlock(&tty->ldisc_mutex);
                tty_ldisc_put(new_ldisc);
+               unlock_kernel();
                return -EIO;
        }
 
@@ -664,6 +682,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
        if (o_work)
                schedule_delayed_work(&o_tty->buf.work, 1);
        mutex_unlock(&tty->ldisc_mutex);
+       unlock_kernel();
        return retval;
 }
 
index c63f3d33914a7def6b4e49d2f3d33a25dbf8fc0c..be492dd664370a787b6da7a2b294b3bf53451de6 100644 (file)
@@ -25,19 +25,21 @@ void tty_port_init(struct tty_port *port)
        init_waitqueue_head(&port->close_wait);
        init_waitqueue_head(&port->delta_msr_wait);
        mutex_init(&port->mutex);
+       mutex_init(&port->buf_mutex);
        spin_lock_init(&port->lock);
        port->close_delay = (50 * HZ) / 100;
        port->closing_wait = (3000 * HZ) / 100;
+       kref_init(&port->kref);
 }
 EXPORT_SYMBOL(tty_port_init);
 
 int tty_port_alloc_xmit_buf(struct tty_port *port)
 {
        /* We may sleep in get_zeroed_page() */
-       mutex_lock(&port->mutex);
+       mutex_lock(&port->buf_mutex);
        if (port->xmit_buf == NULL)
                port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
-       mutex_unlock(&port->mutex);
+       mutex_unlock(&port->buf_mutex);
        if (port->xmit_buf == NULL)
                return -ENOMEM;
        return 0;
@@ -46,15 +48,32 @@ EXPORT_SYMBOL(tty_port_alloc_xmit_buf);
 
 void tty_port_free_xmit_buf(struct tty_port *port)
 {
-       mutex_lock(&port->mutex);
+       mutex_lock(&port->buf_mutex);
        if (port->xmit_buf != NULL) {
                free_page((unsigned long)port->xmit_buf);
                port->xmit_buf = NULL;
        }
-       mutex_unlock(&port->mutex);
+       mutex_unlock(&port->buf_mutex);
 }
 EXPORT_SYMBOL(tty_port_free_xmit_buf);
 
+static void tty_port_destructor(struct kref *kref)
+{
+       struct tty_port *port = container_of(kref, struct tty_port, kref);
+       if (port->xmit_buf)
+               free_page((unsigned long)port->xmit_buf);
+       if (port->ops->destruct)
+               port->ops->destruct(port);
+       else
+               kfree(port);
+}
+
+void tty_port_put(struct tty_port *port)
+{
+       if (port)
+               kref_put(&port->kref, tty_port_destructor);
+}
+EXPORT_SYMBOL(tty_port_put);
 
 /**
  *     tty_port_tty_get        -       get a tty reference
@@ -99,10 +118,11 @@ EXPORT_SYMBOL(tty_port_tty_set);
 
 static void tty_port_shutdown(struct tty_port *port)
 {
+       mutex_lock(&port->mutex);
        if (port->ops->shutdown &&
                test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags))
                        port->ops->shutdown(port);
-
+       mutex_unlock(&port->mutex);
 }
 
 /**
@@ -120,8 +140,10 @@ void tty_port_hangup(struct tty_port *port)
        spin_lock_irqsave(&port->lock, flags);
        port->count = 0;
        port->flags &= ~ASYNC_NORMAL_ACTIVE;
-       if (port->tty)
+       if (port->tty) {
+               set_bit(TTY_IO_ERROR, &port->tty->flags);
                tty_kref_put(port->tty);
+       }
        port->tty = NULL;
        spin_unlock_irqrestore(&port->lock, flags);
        wake_up_interruptible(&port->open_wait);
@@ -198,7 +220,7 @@ EXPORT_SYMBOL(tty_port_lower_dtr_rts);
  *     management of these lines. Note that the dtr/rts raise is done each
  *     iteration as a hangup may have previously dropped them while we wait.
  */
+
 int tty_port_block_til_ready(struct tty_port *port,
                                struct tty_struct *tty, struct file *filp)
 {
@@ -253,7 +275,8 @@ int tty_port_block_til_ready(struct tty_port *port,
                        tty_port_raise_dtr_rts(port);
 
                prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE);
-               /* Check for a hangup or uninitialised port. Return accordingly */
+               /* Check for a hangup or uninitialised port.
+                                                       Return accordingly */
                if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
                        if (port->flags & ASYNC_HUP_NOTIFY)
                                retval = -EAGAIN;
@@ -285,11 +308,11 @@ int tty_port_block_til_ready(struct tty_port *port,
                port->flags |= ASYNC_NORMAL_ACTIVE;
        spin_unlock_irqrestore(&port->lock, flags);
        return retval;
-       
 }
 EXPORT_SYMBOL(tty_port_block_til_ready);
 
-int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, struct file *filp)
+int tty_port_close_start(struct tty_port *port,
+                               struct tty_struct *tty, struct file *filp)
 {
        unsigned long flags;
 
@@ -299,7 +322,7 @@ int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, struct f
                return 0;
        }
 
-       iftty->count == 1 && port->count != 1) {
+       if (tty->count == 1 && port->count != 1) {
                printk(KERN_WARNING
                    "tty_port_close_start: tty->count = 1 port count = %d.\n",
                                                                port->count);
@@ -331,12 +354,20 @@ int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, struct f
                long timeout;
 
                if (bps > 1200)
-                       timeout = max_t(long, (HZ * 10 * port->drain_delay) / bps,
-                                                               HZ / 10);
+                       timeout = max_t(long,
+                               (HZ * 10 * port->drain_delay) / bps, HZ / 10);
                else
                        timeout = 2 * HZ;
                schedule_timeout_interruptible(timeout);
        }
+       /* Flush the ldisc buffering */
+       tty_ldisc_flush(tty);
+
+       /* Drop DTR/RTS if HUPCL is set. This causes any attached modem to
+          hang up the line */
+       if (tty->termios->c_cflag & HUPCL)
+               tty_port_lower_dtr_rts(port);
+
        /* Don't call port->drop for the last reference. Callers will want
           to drop the last active reference in ->shutdown() or the tty
           shutdown path */
@@ -348,11 +379,6 @@ void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
 {
        unsigned long flags;
 
-       tty_ldisc_flush(tty);
-
-       if (tty->termios->c_cflag & HUPCL)
-               tty_port_lower_dtr_rts(port);
-
        spin_lock_irqsave(&port->lock, flags);
        tty->closing = 0;
 
@@ -377,7 +403,42 @@ void tty_port_close(struct tty_port *port, struct tty_struct *tty,
        if (tty_port_close_start(port, tty, filp) == 0)
                return;
        tty_port_shutdown(port);
+       set_bit(TTY_IO_ERROR, &tty->flags);
        tty_port_close_end(port, tty);
        tty_port_tty_set(port, NULL);
 }
 EXPORT_SYMBOL(tty_port_close);
+
+int tty_port_open(struct tty_port *port, struct tty_struct *tty,
+                                                       struct file *filp)
+{
+       spin_lock_irq(&port->lock);
+       if (!tty_hung_up_p(filp))
+               ++port->count;
+       spin_unlock_irq(&port->lock);
+       tty_port_tty_set(port, tty);
+
+       /*
+        * Do the device-specific open only if the hardware isn't
+        * already initialized. Serialize open and shutdown using the
+        * port mutex.
+        */
+
+       mutex_lock(&port->mutex);
+
+       if (!test_bit(ASYNCB_INITIALIZED, &port->flags)) {
+               clear_bit(TTY_IO_ERROR, &tty->flags);
+               if (port->ops->activate) {
+                       int retval = port->ops->activate(port, tty);
+                       if (retval) {
+                               mutex_unlock(&port->mutex);
+                               return retval;
+                       }
+               }
+               set_bit(ASYNCB_INITIALIZED, &port->flags);
+       }
+       mutex_unlock(&port->mutex);
+       return tty_port_block_til_ready(port, tty, filp);
+}
+
+EXPORT_SYMBOL(tty_port_open);
index b8e7c5ae981e5e1e7414444452120705140b6943..f53755533e7e2e05b4343850ed544b10c0429df6 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/sched.h>
 #include <linux/mutex.h>
 #include <linux/seq_file.h>
 #include <linux/serial_reg.h>
@@ -73,11 +74,10 @@ struct uart_icount {
 };
 
 struct sdio_uart_port {
+       struct tty_port         port;
        struct kref             kref;
        struct tty_struct       *tty;
        unsigned int            index;
-       unsigned int            opened;
-       struct mutex            open_lock;
        struct sdio_func        *func;
        struct mutex            func_lock;
        struct task_struct      *in_sdio_uart_irq;
@@ -87,6 +87,7 @@ struct sdio_uart_port {
        struct uart_icount      icount;
        unsigned int            uartclk;
        unsigned int            mctrl;
+       unsigned int            rx_mctrl;
        unsigned int            read_status_mask;
        unsigned int            ignore_status_mask;
        unsigned char           x_char;
@@ -102,7 +103,6 @@ static int sdio_uart_add_port(struct sdio_uart_port *port)
        int index, ret = -EBUSY;
 
        kref_init(&port->kref);
-       mutex_init(&port->open_lock);
        mutex_init(&port->func_lock);
        spin_lock_init(&port->write_lock);
 
@@ -151,6 +151,7 @@ static void sdio_uart_port_put(struct sdio_uart_port *port)
 static void sdio_uart_port_remove(struct sdio_uart_port *port)
 {
        struct sdio_func *func;
+       struct tty_struct *tty;
 
        BUG_ON(sdio_uart_table[port->index] != port);
 
@@ -165,15 +166,19 @@ static void sdio_uart_port_remove(struct sdio_uart_port *port)
         * give up on that port ASAP.
         * Beware: the lock ordering is critical.
         */
-       mutex_lock(&port->open_lock);
+       mutex_lock(&port->port.mutex);
        mutex_lock(&port->func_lock);
        func = port->func;
        sdio_claim_host(func);
        port->func = NULL;
        mutex_unlock(&port->func_lock);
-       if (port->opened)
-               tty_hangup(port->tty);
-       mutex_unlock(&port->open_lock);
+       tty = tty_port_tty_get(&port->port);
+       /* tty_hangup is async so is this safe as is ?? */
+       if (tty) {
+               tty_hangup(tty);
+               tty_kref_put(tty);
+       }
+       mutex_unlock(&port->port.mutex);
        sdio_release_irq(func);
        sdio_disable_func(func);
        sdio_release_host(func);
@@ -217,6 +222,8 @@ static unsigned int sdio_uart_get_mctrl(struct sdio_uart_port *port)
        unsigned char status;
        unsigned int ret;
 
+       /* FIXME: What stops this losing the delta bits and breaking
+          sdio_uart_check_modem_status ? */
        status = sdio_in(port, UART_MSR);
 
        ret = 0;
@@ -391,7 +398,7 @@ static void sdio_uart_stop_rx(struct sdio_uart_port *port)
 static void sdio_uart_receive_chars(struct sdio_uart_port *port,
                                    unsigned int *status)
 {
-       struct tty_struct *tty = port->tty;
+       struct tty_struct *tty = tty_port_tty_get(&port->port);
        unsigned int ch, flag;
        int max_count = 256;
 
@@ -428,24 +435,30 @@ static void sdio_uart_receive_chars(struct sdio_uart_port *port,
                }
 
                if ((*status & port->ignore_status_mask & ~UART_LSR_OE) == 0)
-                       tty_insert_flip_char(tty, ch, flag);
+                       if (tty)
+                               tty_insert_flip_char(tty, ch, flag);
 
                /*
                 * Overrun is special.  Since it's reported immediately,
                 * it doesn't affect the current character.
                 */
                if (*status & ~port->ignore_status_mask & UART_LSR_OE)
-                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+                       if (tty)
+                               tty_insert_flip_char(tty, 0, TTY_OVERRUN);
 
                *status = sdio_in(port, UART_LSR);
        } while ((*status & UART_LSR_DR) && (max_count-- > 0));
-       tty_flip_buffer_push(tty);
+       if (tty) {
+               tty_flip_buffer_push(tty);
+               tty_kref_put(tty);
+       }
 }
 
 static void sdio_uart_transmit_chars(struct sdio_uart_port *port)
 {
        struct circ_buf *xmit = &port->xmit;
        int count;
+       struct tty_struct *tty;
 
        if (port->x_char) {
                sdio_out(port, UART_TX, port->x_char);
@@ -453,8 +466,13 @@ static void sdio_uart_transmit_chars(struct sdio_uart_port *port)
                port->x_char = 0;
                return;
        }
-       if (circ_empty(xmit) || port->tty->stopped || port->tty->hw_stopped) {
+
+       tty = tty_port_tty_get(&port->port);
+
+       if (tty == NULL || circ_empty(xmit) ||
+                               tty->stopped || tty->hw_stopped) {
                sdio_uart_stop_tx(port);
+               tty_kref_put(tty);
                return;
        }
 
@@ -468,15 +486,17 @@ static void sdio_uart_transmit_chars(struct sdio_uart_port *port)
        } while (--count > 0);
 
        if (circ_chars_pending(xmit) < WAKEUP_CHARS)
-               tty_wakeup(port->tty);
+               tty_wakeup(tty);
 
        if (circ_empty(xmit))
                sdio_uart_stop_tx(port);
+       tty_kref_put(tty);
 }
 
 static void sdio_uart_check_modem_status(struct sdio_uart_port *port)
 {
        int status;
+       struct tty_struct *tty;
 
        status = sdio_in(port, UART_MSR);
 
@@ -487,25 +507,39 @@ static void sdio_uart_check_modem_status(struct sdio_uart_port *port)
                port->icount.rng++;
        if (status & UART_MSR_DDSR)
                port->icount.dsr++;
-       if (status & UART_MSR_DDCD)
+       if (status & UART_MSR_DDCD) {
                port->icount.dcd++;
+               /* DCD raise - wake for open */
+               if (status & UART_MSR_DCD)
+                       wake_up_interruptible(&port->port.open_wait);
+               else {
+                       /* DCD drop - hang up if tty attached */
+                       tty = tty_port_tty_get(&port->port);
+                       if (tty) {
+                               tty_hangup(tty);
+                               tty_kref_put(tty);
+                       }
+               }
+       }
        if (status & UART_MSR_DCTS) {
                port->icount.cts++;
-               if (port->tty->termios->c_cflag & CRTSCTS) {
+               tty = tty_port_tty_get(&port->port);
+               if (tty && (tty->termios->c_cflag & CRTSCTS)) {
                        int cts = (status & UART_MSR_CTS);
-                       if (port->tty->hw_stopped) {
+                       if (tty->hw_stopped) {
                                if (cts) {
-                                       port->tty->hw_stopped = 0;
+                                       tty->hw_stopped = 0;
                                        sdio_uart_start_tx(port);
-                                       tty_wakeup(port->tty);
+                                       tty_wakeup(tty);
                                }
                        } else {
                                if (!cts) {
-                                       port->tty->hw_stopped = 1;
+                                       tty->hw_stopped = 1;
                                        sdio_uart_stop_tx(port);
                                }
                        }
                }
+               tty_kref_put(tty);
        }
 }
 
@@ -542,8 +576,62 @@ static void sdio_uart_irq(struct sdio_func *func)
        port->in_sdio_uart_irq = NULL;
 }
 
-static int sdio_uart_startup(struct sdio_uart_port *port)
+static int uart_carrier_raised(struct tty_port *tport)
+{
+       struct sdio_uart_port *port =
+                       container_of(tport, struct sdio_uart_port, port);
+       unsigned int ret = sdio_uart_claim_func(port);
+       if (ret)        /* Missing hardware shoudn't block for carrier */
+               return 1;
+       ret = sdio_uart_get_mctrl(port);
+       sdio_uart_release_func(port);
+       if (ret & TIOCM_CAR)
+               return 1;
+       return 0;
+}
+
+/**
+ *     uart_dtr_rts            -        port helper to set uart signals
+ *     @tport: tty port to be updated
+ *     @onoff: set to turn on DTR/RTS
+ *
+ *     Called by the tty port helpers when the modem signals need to be
+ *     adjusted during an open, close and hangup.
+ */
+
+static void uart_dtr_rts(struct tty_port *tport, int onoff)
+{
+       struct sdio_uart_port *port =
+                       container_of(tport, struct sdio_uart_port, port);
+       int ret = sdio_uart_claim_func(port);
+       if (ret)
+               return;
+       if (onoff == 0)
+               sdio_uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
+       else
+               sdio_uart_set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
+       sdio_uart_release_func(port);
+}
+
+/**
+ *     sdio_uart_activate      -       start up hardware
+ *     @tport: tty port to activate
+ *     @tty: tty bound to this port
+ *
+ *     Activate a tty port. The port locking guarantees us this will be
+ *     run exactly once per set of opens, and if successful will see the
+ *     shutdown method run exactly once to match. Start up and shutdown are
+ *     protected from each other by the internal locking and will not run
+ *     at the same time even during a hangup event.
+ *
+ *     If we successfully start up the port we take an extra kref as we
+ *     will keep it around until shutdown when the kref is dropped.
+ */
+
+static int sdio_uart_activate(struct tty_port *tport, struct tty_struct *tty)
 {
+       struct sdio_uart_port *port =
+                       container_of(tport, struct sdio_uart_port, port);
        unsigned long page;
        int ret;
 
@@ -551,7 +639,7 @@ static int sdio_uart_startup(struct sdio_uart_port *port)
         * Set the TTY IO error marker - we will only clear this
         * once we have successfully opened the port.
         */
-       set_bit(TTY_IO_ERROR, &port->tty->flags);
+       set_bit(TTY_IO_ERROR, &tty->flags);
 
        /* Initialise and allocate the transmit buffer. */
        page = __get_free_page(GFP_KERNEL);
@@ -592,19 +680,19 @@ static int sdio_uart_startup(struct sdio_uart_port *port)
         */
        sdio_out(port, UART_LCR, UART_LCR_WLEN8);
 
-       port->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_RTOIE | UART_IER_UUE;
+       port->ier = UART_IER_RLSI|UART_IER_RDI|UART_IER_RTOIE|UART_IER_UUE;
        port->mctrl = TIOCM_OUT2;
 
-       sdio_uart_change_speed(port, port->tty->termios, NULL);
+       sdio_uart_change_speed(port, tty->termios, NULL);
 
-       if (port->tty->termios->c_cflag & CBAUD)
+       if (tty->termios->c_cflag & CBAUD)
                sdio_uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR);
 
-       if (port->tty->termios->c_cflag & CRTSCTS)
+       if (tty->termios->c_cflag & CRTSCTS)
                if (!(sdio_uart_get_mctrl(port) & TIOCM_CTS))
-                       port->tty->hw_stopped = 1;
+                       tty->hw_stopped = 1;
 
-       clear_bit(TTY_IO_ERROR, &port->tty->flags);
+       clear_bit(TTY_IO_ERROR, &tty->flags);
 
        /* Kick the IRQ handler once while we're still holding the host lock */
        sdio_uart_irq(port->func);
@@ -621,8 +709,20 @@ err1:
        return ret;
 }
 
-static void sdio_uart_shutdown(struct sdio_uart_port *port)
+/**
+ *     sdio_uart_shutdown      -       stop hardware
+ *     @tport: tty port to shut down
+ *
+ *     Deactivate a tty port. The port locking guarantees us this will be
+ *     run only if a successful matching activate already ran. The two are
+ *     protected from each other by the internal locking and will not run
+ *     at the same time even during a hangup event.
+ */
+
+static void sdio_uart_shutdown(struct tty_port *tport)
 {
+       struct sdio_uart_port *port =
+                       container_of(tport, struct sdio_uart_port, port);
        int ret;
 
        ret = sdio_uart_claim_func(port);
@@ -631,12 +731,6 @@ static void sdio_uart_shutdown(struct sdio_uart_port *port)
 
        sdio_uart_stop_rx(port);
 
-       /* TODO: wait here for TX FIFO to drain */
-
-       /* Turn off DTR and RTS early. */
-       if (port->tty->termios->c_cflag & HUPCL)
-               sdio_uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
-
        /* Disable interrupts from this port */
        sdio_release_irq(port->func);
        port->ier = 0;
@@ -661,77 +755,70 @@ skip:
        free_page((unsigned long)port->xmit.buf);
 }
 
-static int sdio_uart_open(struct tty_struct *tty, struct file *filp)
+/**
+ *     sdio_uart_install       -       install method
+ *     @driver: the driver in use (sdio_uart in our case)
+ *     @tty: the tty being bound
+ *
+ *     Look up and bind the tty and the driver together. Initialize
+ *     any needed private data (in our case the termios)
+ */
+
+static int sdio_uart_install(struct tty_driver *driver, struct tty_struct *tty)
 {
-       struct sdio_uart_port *port;
-       int ret;
+       int idx = tty->index;
+       struct sdio_uart_port *port = sdio_uart_port_get(idx);
+       int ret = tty_init_termios(tty);
+
+       if (ret == 0) {
+               tty_driver_kref_get(driver);
+               tty->count++;
+               /* This is the ref sdio_uart_port get provided */
+               tty->driver_data = port;
+               driver->ttys[idx] = tty;
+       } else
+               sdio_uart_port_put(port);
+       return ret;
+}
 
-       port = sdio_uart_port_get(tty->index);
-       if (!port)
-               return -ENODEV;
+/**
+ *     sdio_uart_cleanup       -       called on the last tty kref drop
+ *     @tty: the tty being destroyed
+ *
+ *     Called asynchronously when the last reference to the tty is dropped.
+ *     We cannot destroy the tty->driver_data port kref until this point
+ */
 
-       mutex_lock(&port->open_lock);
+static void sdio_uart_cleanup(struct tty_struct *tty)
+{
+       struct sdio_uart_port *port = tty->driver_data;
+       tty->driver_data = NULL;        /* Bug trap */
+       sdio_uart_port_put(port);
+}
 
-       /*
-        * Make sure not to mess up with a dead port
-        * which has not been closed yet.
-        */
-       if (tty->driver_data && tty->driver_data != port) {
-               mutex_unlock(&port->open_lock);
-               sdio_uart_port_put(port);
-               return -EBUSY;
-       }
+/*
+ *     Open/close/hangup is now entirely boilerplate
+ */
 
-       if (!port->opened) {
-               tty->driver_data = port;
-               port->tty = tty;
-               ret = sdio_uart_startup(port);
-               if (ret) {
-                       tty->driver_data = NULL;
-                       port->tty = NULL;
-                       mutex_unlock(&port->open_lock);
-                       sdio_uart_port_put(port);
-                       return ret;
-               }
-       }
-       port->opened++;
-       mutex_unlock(&port->open_lock);
-       return 0;
+static int sdio_uart_open(struct tty_struct *tty, struct file *filp)
+{
+       struct sdio_uart_port *port = tty->driver_data;
+       return tty_port_open(&port->port, tty, filp);
 }
 
 static void sdio_uart_close(struct tty_struct *tty, struct file * filp)
 {
        struct sdio_uart_port *port = tty->driver_data;
+       tty_port_close(&port->port, tty, filp);
+}
 
-       if (!port)
-               return;
-
-       mutex_lock(&port->open_lock);
-       BUG_ON(!port->opened);
-
-       /*
-        * This is messy.  The tty layer calls us even when open()
-        * returned an error.  Ignore this close request if tty->count
-        * is larger than port->count.
-        */
-       if (tty->count > port->opened) {
-               mutex_unlock(&port->open_lock);
-               return;
-       }
-
-       if (--port->opened == 0) {
-               tty->closing = 1;
-               sdio_uart_shutdown(port);
-               tty_ldisc_flush(tty);
-               port->tty = NULL;
-               tty->driver_data = NULL;
-               tty->closing = 0;
-       }
-       mutex_unlock(&port->open_lock);
-       sdio_uart_port_put(port);
+static void sdio_uart_hangup(struct tty_struct *tty)
+{
+       struct sdio_uart_port *port = tty->driver_data;
+       tty_port_hangup(&port->port);
 }
 
-static int sdio_uart_write(struct tty_struct * tty, const unsigned char *buf,
+static int sdio_uart_write(struct tty_struct *tty, const unsigned char *buf,
                           int count)
 {
        struct sdio_uart_port *port = tty->driver_data;
@@ -756,7 +843,7 @@ static int sdio_uart_write(struct tty_struct * tty, const unsigned char *buf,
        }
        spin_unlock(&port->write_lock);
 
-       if ( !(port->ier & UART_IER_THRI)) {
+       if (!(port->ier & UART_IER_THRI)) {
                int err = sdio_uart_claim_func(port);
                if (!err) {
                        sdio_uart_start_tx(port);
@@ -843,17 +930,12 @@ static void sdio_uart_unthrottle(struct tty_struct *tty)
        sdio_uart_release_func(port);
 }
 
-static void sdio_uart_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
+static void sdio_uart_set_termios(struct tty_struct *tty,
+                                               struct ktermios *old_termios)
 {
        struct sdio_uart_port *port = tty->driver_data;
        unsigned int cflag = tty->termios->c_cflag;
 
-#define RELEVANT_IFLAG(iflag)  ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
-
-       if ((cflag ^ old_termios->c_cflag) == 0 &&
-           RELEVANT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0)
-               return;
-
        if (sdio_uart_claim_func(port) != 0)
                return;
 
@@ -928,7 +1010,7 @@ static int sdio_uart_tiocmset(struct tty_struct *tty, struct file *file,
        int result;
 
        result = sdio_uart_claim_func(port);
-       if(!result) {
+       if (!result) {
                sdio_uart_update_mctrl(port, set, clear);
                sdio_uart_release_func(port);
        }
@@ -946,7 +1028,7 @@ static int sdio_uart_proc_show(struct seq_file *m, void *v)
                struct sdio_uart_port *port = sdio_uart_port_get(i);
                if (port) {
                        seq_printf(m, "%d: uart:SDIO", i);
-                       if(capable(CAP_SYS_ADMIN)) {
+                       if (capable(CAP_SYS_ADMIN)) {
                                seq_printf(m, " tx:%d rx:%d",
                                              port->icount.tx, port->icount.rx);
                                if (port->icount.frame)
@@ -994,6 +1076,13 @@ static const struct file_operations sdio_uart_proc_fops = {
        .release        = single_release,
 };
 
+static const struct tty_port_operations sdio_uart_port_ops = {
+       .dtr_rts = uart_dtr_rts,
+       .carrier_raised = uart_carrier_raised,
+       .shutdown = sdio_uart_shutdown,
+       .activate = sdio_uart_activate,
+};
+
 static const struct tty_operations sdio_uart_ops = {
        .open                   = sdio_uart_open,
        .close                  = sdio_uart_close,
@@ -1004,9 +1093,12 @@ static const struct tty_operations sdio_uart_ops = {
        .throttle               = sdio_uart_throttle,
        .unthrottle             = sdio_uart_unthrottle,
        .set_termios            = sdio_uart_set_termios,
+       .hangup                 = sdio_uart_hangup,
        .break_ctl              = sdio_uart_break_ctl,
        .tiocmget               = sdio_uart_tiocmget,
        .tiocmset               = sdio_uart_tiocmset,
+       .install                = sdio_uart_install,
+       .cleanup                = sdio_uart_cleanup,
        .proc_fops              = &sdio_uart_proc_fops,
 };
 
@@ -1043,7 +1135,7 @@ static int sdio_uart_probe(struct sdio_func *func,
                }
                if (!tpl) {
                        printk(KERN_WARNING
-                              "%s: can't find tuple 0x91 subtuple 0 (SUBTPL_SIOREG) for GPS class\n",
+       "%s: can't find tuple 0x91 subtuple 0 (SUBTPL_SIOREG) for GPS class\n",
                               sdio_func_id(func));
                        kfree(port);
                        return -EINVAL;
@@ -1068,13 +1160,16 @@ static int sdio_uart_probe(struct sdio_func *func,
 
        port->func = func;
        sdio_set_drvdata(func, port);
+       tty_port_init(&port->port);
+       port->port.ops = &sdio_uart_port_ops;
 
        ret = sdio_uart_add_port(port);
        if (ret) {
                kfree(port);
        } else {
                struct device *dev;
-               dev = tty_register_device(sdio_uart_tty_driver, port->index, &func->dev);
+               dev = tty_register_device(sdio_uart_tty_driver,
+                                               port->index, &func->dev);
                if (IS_ERR(dev)) {
                        sdio_uart_port_remove(port);
                        ret = PTR_ERR(dev);
index 737b4c9609712532e96c4d277b093014f7b0d249..c3e37c8e7e26a8b8ecc4a767561aea15b2378909 100644 (file)
@@ -1339,14 +1339,12 @@ static void serial8250_start_tx(struct uart_port *port)
                serial_out(up, UART_IER, up->ier);
 
                if (up->bugs & UART_BUG_TXEN) {
-                       unsigned char lsr, iir;
+                       unsigned char lsr;
                        lsr = serial_in(up, UART_LSR);
                        up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
-                       iir = serial_in(up, UART_IIR) & 0x0f;
                        if ((up->port.type == PORT_RM9000) ?
-                               (lsr & UART_LSR_THRE &&
-                               (iir == UART_IIR_NO_INT || iir == UART_IIR_THRI)) :
-                               (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT))
+                               (lsr & UART_LSR_THRE) :
+                               (lsr & UART_LSR_TEMT))
                                transmit_chars(up);
                }
        }
@@ -2646,7 +2644,7 @@ static void __init serial8250_isa_init_ports(void)
 {
        struct uart_8250_port *up;
        static int first = 1;
-       int i;
+       int i, irqflag = 0;
 
        if (!first)
                return;
@@ -2670,6 +2668,9 @@ static void __init serial8250_isa_init_ports(void)
                up->port.ops = &serial8250_pops;
        }
 
+       if (share_irqs)
+               irqflag = IRQF_SHARED;
+
        for (i = 0, up = serial8250_ports;
             i < ARRAY_SIZE(old_serial_port) && i < nr_uarts;
             i++, up++) {
@@ -2683,8 +2684,7 @@ static void __init serial8250_isa_init_ports(void)
                up->port.iotype   = old_serial_port[i].io_type;
                up->port.regshift = old_serial_port[i].iomem_reg_shift;
                set_io_from_upio(&up->port);
-               if (share_irqs)
-                       up->port.irqflags |= IRQF_SHARED;
+               up->port.irqflags |= irqflag;
        }
 }
 
@@ -2940,10 +2940,13 @@ static int __devinit serial8250_probe(struct platform_device *dev)
 {
        struct plat_serial8250_port *p = dev->dev.platform_data;
        struct uart_port port;
-       int ret, i;
+       int ret, i, irqflag = 0;
 
        memset(&port, 0, sizeof(struct uart_port));
 
+       if (share_irqs)
+               irqflag = IRQF_SHARED;
+
        for (i = 0; p && p->flags != 0; p++, i++) {
                port.iobase             = p->iobase;
                port.membase            = p->membase;
@@ -2960,8 +2963,7 @@ static int __devinit serial8250_probe(struct platform_device *dev)
                port.serial_in          = p->serial_in;
                port.serial_out         = p->serial_out;
                port.dev                = &dev->dev;
-               if (share_irqs)
-                       port.irqflags |= IRQF_SHARED;
+               port.irqflags           |= irqflag;
                ret = serial8250_register_port(&port);
                if (ret < 0) {
                        dev_err(&dev->dev, "unable to register port at index %d "
index 4e5f3bde0461ca4c8eb4638bcc11643466c697ab..38a509c684cd297f0dfaa18bf67279bdfcd9d9b8 100644 (file)
@@ -138,7 +138,6 @@ struct jsm_board
        u32             nasync;         /* Number of ports on card */
 
        u32             irq;            /* Interrupt request number */
-       u64             intr_count;     /* Count of interrupts */
 
        u64             membase;        /* Start of base memory of the card */
        u64             membase_end;    /* End of base memory of the card */
@@ -206,8 +205,6 @@ struct jsm_channel {
 
        u64             ch_close_delay; /* How long we should drop RTS/DTR for */
 
-       u64             ch_cpstime;     /* Time for CPS calculations    */
-
        tcflag_t        ch_c_iflag;     /* channel iflags               */
        tcflag_t        ch_c_cflag;     /* channel cflags               */
        tcflag_t        ch_c_oflag;     /* channel oflags               */
@@ -215,11 +212,6 @@ struct jsm_channel {
        u8              ch_stopc;       /* Stop character               */
        u8              ch_startc;      /* Start character              */
 
-       u32             ch_old_baud;    /* Cache of the current baud */
-       u32             ch_custom_speed;/* Custom baud, if set */
-
-       u32             ch_wopen;       /* Waiting for open process cnt */
-
        u8              ch_mostat;      /* FEP output modem status      */
        u8              ch_mistat;      /* FEP input modem status       */
 
index b3604aa322a46ed5f7801f728c209cd67ce6c7ab..108c3e0471fd523ab849d7ebc58d702c0b3ac1d4 100644 (file)
@@ -48,6 +48,17 @@ struct uart_driver jsm_uart_driver = {
        .nr             = NR_PORTS,
 };
 
+static pci_ers_result_t jsm_io_error_detected(struct pci_dev *pdev,
+                                       pci_channel_state_t state);
+static pci_ers_result_t jsm_io_slot_reset(struct pci_dev *pdev);
+static void jsm_io_resume(struct pci_dev *pdev);
+
+static struct pci_error_handlers jsm_err_handler = {
+       .error_detected = jsm_io_error_detected,
+       .slot_reset = jsm_io_slot_reset,
+       .resume = jsm_io_resume,
+};
+
 int jsm_debug;
 module_param(jsm_debug, int, 0);
 MODULE_PARM_DESC(jsm_debug, "Driver debugging level");
@@ -123,7 +134,7 @@ static int __devinit jsm_probe_one(struct pci_dev *pdev, const struct pci_device
        }
 
        rc = request_irq(brd->irq, brd->bd_ops->intr,
-                       IRQF_DISABLED|IRQF_SHARED, "JSM", brd);
+                       IRQF_SHARED, "JSM", brd);
        if (rc) {
                printk(KERN_WARNING "Failed to hook IRQ %d\n",brd->irq);
                goto out_iounmap;
@@ -164,6 +175,7 @@ static int __devinit jsm_probe_one(struct pci_dev *pdev, const struct pci_device
        }
 
        pci_set_drvdata(pdev, brd);
+       pci_save_state(pdev);
 
        return 0;
  out_free_irq:
@@ -222,8 +234,42 @@ static struct pci_driver jsm_driver = {
        .id_table       = jsm_pci_tbl,
        .probe          = jsm_probe_one,
        .remove         = __devexit_p(jsm_remove_one),
+       .err_handler    = &jsm_err_handler,
 };
 
+static pci_ers_result_t jsm_io_error_detected(struct pci_dev *pdev,
+                                       pci_channel_state_t state)
+{
+       struct jsm_board *brd = pci_get_drvdata(pdev);
+
+       jsm_remove_uart_port(brd);
+
+       return PCI_ERS_RESULT_NEED_RESET;
+}
+
+static pci_ers_result_t jsm_io_slot_reset(struct pci_dev *pdev)
+{
+       int rc;
+
+       rc = pci_enable_device(pdev);
+
+       if (rc)
+               return PCI_ERS_RESULT_DISCONNECT;
+
+       pci_set_master(pdev);
+
+       return PCI_ERS_RESULT_RECOVERED;
+}
+
+static void jsm_io_resume(struct pci_dev *pdev)
+{
+       struct jsm_board *brd = pci_get_drvdata(pdev);
+
+       pci_restore_state(pdev);
+
+       jsm_uart_port_init(brd);
+}
+
 static int __init jsm_init_module(void)
 {
        int rc;
index b4b124e4828fc31f85de069a554c980f60ccad65..7960d9633c15a2a18ad53b57540b6d316ca010bf 100644 (file)
@@ -954,13 +954,8 @@ static void neo_param(struct jsm_channel *ch)
                ch->ch_flags |= (CH_BAUD0);
                ch->ch_mostat &= ~(UART_MCR_RTS | UART_MCR_DTR);
                neo_assert_modem_signals(ch);
-               ch->ch_old_baud = 0;
                return;
 
-       } else if (ch->ch_custom_speed) {
-                       baud = ch->ch_custom_speed;
-                       if (ch->ch_flags & CH_BAUD0)
-                               ch->ch_flags &= ~(CH_BAUD0);
        } else {
                int i;
                unsigned int cflag;
@@ -1045,7 +1040,6 @@ static void neo_param(struct jsm_channel *ch)
        quot = ch->ch_bd->bd_dividend / baud;
 
        if (quot != 0) {
-               ch->ch_old_baud = baud;
                writeb(UART_LCR_DLAB, &ch->ch_neo_uart->lcr);
                writeb((quot & 0xff), &ch->ch_neo_uart->txrx);
                writeb((quot >> 8), &ch->ch_neo_uart->ier);
@@ -1123,8 +1117,6 @@ static irqreturn_t neo_intr(int irq, void *voidbrd)
        unsigned long lock_flags2;
        int outofloop_count = 0;
 
-       brd->intr_count++;
-
        /* Lock out the slow poller from running on this board. */
        spin_lock_irqsave(&brd->bd_intr_lock, lock_flags);
 
index 7439c0373620b60f0351b2cccda143d1b023a642..cd95e215550d70fdeac7c1280264c94a327bc880 100644 (file)
@@ -296,8 +296,6 @@ static void jsm_tty_close(struct uart_port *port)
                bd->bd_ops->assert_modem_signals(channel);
        }
 
-       channel->ch_old_baud = 0;
-
        /* Turn off UART interrupts for this port */
        channel->ch_bd->bd_ops->uart_off(channel);
 
@@ -432,7 +430,7 @@ int __devinit jsm_tty_init(struct jsm_board *brd)
        return 0;
 }
 
-int __devinit jsm_uart_port_init(struct jsm_board *brd)
+int jsm_uart_port_init(struct jsm_board *brd)
 {
        int i;
        unsigned int line;
@@ -472,7 +470,7 @@ int __devinit jsm_uart_port_init(struct jsm_board *brd)
                if (uart_add_one_port (&jsm_uart_driver, &brd->channels[i]->uart_port))
                        printk(KERN_INFO "jsm: add device failed\n");
                else
-                       printk(KERN_INFO "Added device \n");
+                       printk(KERN_INFO "jsm: Port %d added\n", i);
        }
 
        jsm_printk(INIT, INFO, &brd->pci_dev, "finish\n");
index b8629d74f6a2818fb30a9ba7a0d9f5b82e9eae05..4a821046baae0124e6bb9a36824979d49e69952e 100644 (file)
@@ -438,6 +438,7 @@ serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios,
        unsigned char cval, fcr = 0;
        unsigned long flags;
        unsigned int baud, quot;
+       unsigned int dll;
 
        switch (termios->c_cflag & CSIZE) {
        case CS5:
@@ -534,10 +535,18 @@ serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios,
        else
                up->mcr &= ~UART_MCR_AFE;
 
-       serial_out(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
+       serial_out(up, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */
        serial_out(up, UART_DLL, quot & 0xff);          /* LS of divisor */
+
+       /*
+        * work around Errata #75 according to Intel(R) PXA27x Processor Family
+        * Specification Update (Nov 2005)
+        */
+       dll = serial_in(up, UART_DLL);
+       WARN_ON(dll != (quot & 0xff));
+
        serial_out(up, UART_DLM, quot >> 8);            /* MS of divisor */
-       serial_out(up, UART_LCR, cval);         /* reset DLAB */
+       serial_out(up, UART_LCR, cval);                 /* reset DLAB */
        up->lcr = cval;                                 /* Save LCR */
        serial_pxa_set_mctrl(&up->port, up->port.mctrl);
        serial_out(up, UART_FCR, fcr);
index dcc72444e8e7015e904c70d726a83873dbeff21e..047530b285bb3a50ddf15d8804080980d9539978 100644 (file)
@@ -342,11 +342,11 @@ uart_get_baud_rate(struct uart_port *port, struct ktermios *termios,
 
        if (flags == UPF_SPD_HI)
                altbaud = 57600;
-       if (flags == UPF_SPD_VHI)
+       else if (flags == UPF_SPD_VHI)
                altbaud = 115200;
-       if (flags == UPF_SPD_SHI)
+       else if (flags == UPF_SPD_SHI)
                altbaud = 230400;
-       if (flags == UPF_SPD_WARP)
+       else if (flags == UPF_SPD_WARP)
                altbaud = 460800;
 
        for (try = 0; try < 2; try++) {
@@ -1217,9 +1217,8 @@ static void uart_set_termios(struct tty_struct *tty,
        /* Handle transition to B0 status */
        if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD))
                uart_clear_mctrl(state->uart_port, TIOCM_RTS | TIOCM_DTR);
-
        /* Handle transition away from B0 status */
-       if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
+       else if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
                unsigned int mask = TIOCM_DTR;
                if (!(cflag & CRTSCTS) ||
                    !test_bit(TTY_THROTTLED, &tty->flags))
@@ -1234,9 +1233,8 @@ static void uart_set_termios(struct tty_struct *tty,
                __uart_start(tty);
                spin_unlock_irqrestore(&state->uart_port->lock, flags);
        }
-
        /* Handle turning on CRTSCTS */
-       if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) {
+       else if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) {
                spin_lock_irqsave(&state->uart_port->lock, flags);
                if (!(state->uart_port->ops->get_mctrl(state->uart_port) & TIOCM_CTS)) {
                        tty->hw_stopped = 1;
@@ -2344,7 +2342,7 @@ static const struct tty_operations uart_ops = {
  */
 int uart_register_driver(struct uart_driver *drv)
 {
-       struct tty_driver *normal = NULL;
+       struct tty_driver *normal;
        int i, retval;
 
        BUG_ON(drv->state);
@@ -2354,13 +2352,12 @@ int uart_register_driver(struct uart_driver *drv)
         * we have a large number of ports to handle.
         */
        drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL);
-       retval = -ENOMEM;
        if (!drv->state)
                goto out;
 
-       normal  = alloc_tty_driver(drv->nr);
+       normal = alloc_tty_driver(drv->nr);
        if (!normal)
-               goto out;
+               goto out_kfree;
 
        drv->tty_driver = normal;
 
@@ -2393,12 +2390,14 @@ int uart_register_driver(struct uart_driver *drv)
        }
 
        retval = tty_register_driver(normal);
- out:
-       if (retval < 0) {
-               put_tty_driver(normal);
-               kfree(drv->state);
-       }
-       return retval;
+       if (retval >= 0)
+               return retval;
+
+       put_tty_driver(normal);
+out_kfree:
+       kfree(drv->state);
+out:
+       return -ENOMEM;
 }
 
 /**
index 80f59b6350cbdcee5a9864ef51990c51e2309ad4..4cdb975caa89a96a897451ba57203e97968a7bdc 100644 (file)
@@ -501,12 +501,13 @@ static int opticon_resume(struct usb_interface *intf)
        struct usb_serial_port *port = serial->port[0];
        int result;
 
-       mutex_lock(&port->mutex);
-       if (port->port.count)
+       mutex_lock(&port->port.mutex);
+       /* This is protected by the port mutex against close/open */
+       if (test_bit(ASYNCB_INITIALIZED, &port->port.flags))
                result = usb_submit_urb(priv->bulk_read_urb, GFP_NOIO);
        else
                result = 0;
-       mutex_unlock(&port->mutex);
+       mutex_unlock(&port->port.mutex);
        return result;
 }
 
index bd3fa7ff15b12166bf0cf2ad86f3214144f914c0..4543f359be75ea9d423d12dc700d9c1cd479e5e6 100644 (file)
@@ -247,96 +247,66 @@ static int serial_install(struct tty_driver *driver, struct tty_struct *tty)
        return retval;
 }
 
-static int serial_open(struct tty_struct *tty, struct file *filp)
+static int serial_activate(struct tty_port *tport, struct tty_struct *tty)
 {
-       struct usb_serial_port *port = tty->driver_data;
+       struct usb_serial_port *port =
+               container_of(tport, struct usb_serial_port, port);
        struct usb_serial *serial = port->serial;
        int retval;
 
-       dbg("%s - port %d", __func__, port->number);
-
-       spin_lock_irq(&port->port.lock);
-       if (!tty_hung_up_p(filp))
-               ++port->port.count;
-       spin_unlock_irq(&port->port.lock);
-       tty_port_tty_set(&port->port, tty);
+       mutex_lock(&serial->disc_mutex);
+       if (serial->disconnected)
+               retval = -ENODEV;
+       else
+               retval = port->serial->type->open(tty, port);
+       mutex_unlock(&serial->disc_mutex);
+       return retval;
+}
 
-       /* Do the device-specific open only if the hardware isn't
-        * already initialized.
-        */
-       if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) {
-               if (mutex_lock_interruptible(&port->mutex))
-                       return -ERESTARTSYS;
-               mutex_lock(&serial->disc_mutex);
-               if (serial->disconnected)
-                       retval = -ENODEV;
-               else
-                       retval = port->serial->type->open(tty, port);
-               mutex_unlock(&serial->disc_mutex);
-               mutex_unlock(&port->mutex);
-               if (retval)
-                       return retval;
-               set_bit(ASYNCB_INITIALIZED, &port->port.flags);
-       }
+static int serial_open(struct tty_struct *tty, struct file *filp)
+{
+       struct usb_serial_port *port = tty->driver_data;
 
-       /* Now do the correct tty layer semantics */
-       retval = tty_port_block_til_ready(&port->port, tty, filp);
-       return retval;
+       dbg("%s - port %d", __func__, port->number);
+       return tty_port_open(&port->port, tty, filp);
 }
 
 /**
  * serial_down - shut down hardware
- * @port: port to shut down
+ * @tport: tty port to shut down
  *
  * Shut down a USB serial port unless it is the console.  We never
- * shut down the console hardware as it will always be in use.
+ * shut down the console hardware as it will always be in use. Serialized
+ * against activate by the tport mutex and kept to matching open/close pairs
+ * of calls by the ASYNCB_INITIALIZED flag.
  */
-static void serial_down(struct usb_serial_port *port)
+static void serial_down(struct tty_port *tport)
 {
+       struct usb_serial_port *port =
+               container_of(tport, struct usb_serial_port, port);
        struct usb_serial_driver *drv = port->serial->type;
-
        /*
         * The console is magical.  Do not hang up the console hardware
         * or there will be tears.
         */
        if (port->console)
                return;
-
-       /* Don't call the close method if the hardware hasn't been
-        * initialized.
-        */
-       if (!test_and_clear_bit(ASYNCB_INITIALIZED, &port->port.flags))
-               return;
-
-       mutex_lock(&port->mutex);
        if (drv->close)
                drv->close(port);
-       mutex_unlock(&port->mutex);
 }
 
 static void serial_hangup(struct tty_struct *tty)
 {
        struct usb_serial_port *port = tty->driver_data;
-
        dbg("%s - port %d", __func__, port->number);
-
-       serial_down(port);
        tty_port_hangup(&port->port);
 }
 
 static void serial_close(struct tty_struct *tty, struct file *filp)
 {
        struct usb_serial_port *port = tty->driver_data;
-
        dbg("%s - port %d", __func__, port->number);
-
-       if (tty_hung_up_p(filp))
-               return;
-       if (tty_port_close_start(&port->port, tty, filp) == 0)
-               return;
-       serial_down(port);
-       tty_port_close_end(&port->port, tty);
-       tty_port_tty_set(&port->port, NULL);
+       tty_port_close(&port->port, tty, filp);
 }
 
 /**
@@ -725,6 +695,8 @@ static void serial_dtr_rts(struct tty_port *port, int on)
 static const struct tty_port_operations serial_port_ops = {
        .carrier_raised = serial_carrier_raised,
        .dtr_rts = serial_dtr_rts,
+       .activate = serial_activate,
+       .shutdown = serial_down,
 };
 
 int usb_serial_probe(struct usb_interface *interface,
@@ -923,7 +895,8 @@ int usb_serial_probe(struct usb_interface *interface,
                port->port.ops = &serial_port_ops;
                port->serial = serial;
                spin_lock_init(&port->lock);
-               mutex_init(&port->mutex);
+               /* Keep this for private driver use for the moment but
+                  should probably go away */
                INIT_WORK(&port->work, usb_serial_port_work);
                serial->port[i] = port;
                port->dev.parent = &interface->dev;
index d5f8c96964be9a25f8235c869472b95a77ebbecc..8882ecc0f1bfbec879c7b9c27795ac8b5dd9f63a 100644 (file)
@@ -517,11 +517,23 @@ int devpts_pty_new(struct inode *ptmx_inode, struct tty_struct *tty)
 
 struct tty_struct *devpts_get_tty(struct inode *pts_inode, int number)
 {
+       struct dentry *dentry;
+       struct tty_struct *tty;
+
        BUG_ON(pts_inode->i_rdev == MKDEV(TTYAUX_MAJOR, PTMX_MINOR));
 
+       /* Ensure dentry has not been deleted by devpts_pty_kill() */
+       dentry = d_find_alias(pts_inode);
+       if (!dentry)
+               return NULL;
+
+       tty = NULL;
        if (pts_inode->i_sb->s_magic == DEVPTS_SUPER_MAGIC)
-               return (struct tty_struct *)pts_inode->i_private;
-       return NULL;
+               tty = (struct tty_struct *)pts_inode->i_private;
+
+       dput(dentry);
+
+       return tty;
 }
 
 void devpts_pty_kill(struct tty_struct *tty)
index 5a5385749e1636a5c327c1c728243eadad25e0af..f72914db2a115f0fb7ad2b074300272f699c696b 100644 (file)
@@ -214,7 +214,6 @@ unifdef-y += futex.h
 unifdef-y += fs.h
 unifdef-y += gameport.h
 unifdef-y += generic_serial.h
-unifdef-y += hayesesp.h
 unifdef-y += hdlcdrv.h
 unifdef-y += hdlc.h
 unifdef-y += hdreg.h
diff --git a/include/linux/hayesesp.h b/include/linux/hayesesp.h
deleted file mode 100644 (file)
index 92b08cf..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-#ifndef HAYESESP_H
-#define HAYESESP_H
-
-struct hayes_esp_config {
-       short flow_on;
-       short flow_off;
-       short rx_trigger;
-       short tx_trigger;
-       short pio_threshold;
-       unsigned char rx_timeout;
-       char dma_channel;
-};
-
-#ifdef __KERNEL__
-
-#define ESP_DMA_CHANNEL   0
-#define ESP_RX_TRIGGER    768
-#define ESP_TX_TRIGGER    768
-#define ESP_FLOW_OFF      1016
-#define ESP_FLOW_ON       944
-#define ESP_RX_TMOUT      128
-#define ESP_PIO_THRESHOLD 32
-
-#define ESP_IN_MAJOR   57      /* major dev # for dial in */
-#define ESP_OUT_MAJOR  58      /* major dev # for dial out */
-#define ESPC_SCALE     3
-#define UART_ESI_BASE  0x00
-#define UART_ESI_SID   0x01
-#define UART_ESI_RX    0x02
-#define UART_ESI_TX    0x02
-#define UART_ESI_CMD1  0x04
-#define UART_ESI_CMD2  0x05
-#define UART_ESI_STAT1 0x04
-#define UART_ESI_STAT2 0x05
-#define UART_ESI_RWS   0x07
-
-#define UART_IER_DMA_TMOUT     0x80
-#define UART_IER_DMA_TC                0x08
-
-#define ESI_SET_IRQ            0x04
-#define ESI_SET_DMA_TMOUT      0x05
-#define ESI_SET_SRV_MASK       0x06
-#define ESI_SET_ERR_MASK       0x07
-#define ESI_SET_FLOW_CNTL      0x08
-#define ESI_SET_FLOW_CHARS     0x09
-#define ESI_SET_FLOW_LVL       0x0a
-#define ESI_SET_TRIGGER                0x0b
-#define ESI_SET_RX_TIMEOUT     0x0c
-#define ESI_SET_FLOW_TMOUT     0x0d
-#define ESI_WRITE_UART         0x0e
-#define ESI_READ_UART          0x0f
-#define ESI_SET_MODE           0x10
-#define ESI_GET_ERR_STAT       0x12
-#define ESI_GET_UART_STAT      0x13
-#define ESI_GET_RX_AVAIL       0x14
-#define ESI_GET_TX_AVAIL       0x15
-#define ESI_START_DMA_RX       0x16
-#define ESI_START_DMA_TX       0x17
-#define ESI_ISSUE_BREAK                0x1a
-#define ESI_FLUSH_RX           0x1b
-#define ESI_FLUSH_TX           0x1c
-#define ESI_SET_BAUD           0x1d
-#define ESI_SET_ENH_IRQ                0x1f
-#define ESI_SET_REINTR         0x20
-#define ESI_SET_PRESCALAR      0x23
-#define ESI_NO_COMMAND         0xff
-
-#define ESP_STAT_RX_TIMEOUT    0x01
-#define ESP_STAT_DMA_RX                0x02
-#define ESP_STAT_DMA_TX                0x04
-#define ESP_STAT_NEVER_DMA      0x08
-#define ESP_STAT_USE_PIO        0x10
-
-#define ESP_MAGIC              0x53ee
-#define ESP_XMIT_SIZE          4096
-
-struct esp_struct {
-       int                     magic;
-       struct tty_port         port;
-       spinlock_t              lock;
-       int                     io_port;
-       int                     irq;
-       int                     read_status_mask;
-       int                     ignore_status_mask;
-       int                     timeout;
-       int                     stat_flags;
-       int                     custom_divisor;
-       int                     close_delay;
-       unsigned short          closing_wait;
-       unsigned short          closing_wait2;
-       int                     IER;    /* Interrupt Enable Register */
-       int                     MCR;    /* Modem control register */
-       unsigned long           last_active;
-       int                     line;
-       unsigned char           *xmit_buf;
-       int                     xmit_head;
-       int                     xmit_tail;
-       int                     xmit_cnt;
-       wait_queue_head_t       break_wait;
-       struct async_icount     icount; /* kernel counters for the 4 input interrupts */
-       struct hayes_esp_config config; /* port configuration */
-       struct esp_struct       *next_port; /* For the linked list */
-};
-
-struct esp_pio_buffer {
-       unsigned char data[1024];
-       struct esp_pio_buffer *next;
-};
-
-#endif /* __KERNEL__ */
-
-
-#endif /* ESP_H */
-
index bbd42197298f14b95f78ffcc24d6d2db508de56f..b92e0565063939ede488f0764011614999e0c148 100644 (file)
@@ -67,6 +67,7 @@
 
 #define                FIRMWARE_LOADED         0x0001
 #define                BOARD_ACTIVE            0x0002
+#define                BOARD_INIT              0x0004
 
        /* isi_port status bitmap  */
 
index f0f43d08d8b8765911d51f681034841a73b1c239..405a9035fe40601114e02d77a98aa0090bcd8646 100644 (file)
@@ -190,9 +190,17 @@ struct tty_port_operations {
        /* Control the DTR line */
        void (*dtr_rts)(struct tty_port *port, int raise);
        /* Called when the last close completes or a hangup finishes
-          IFF the port was initialized. Do not use to free resources */
+          IFF the port was initialized. Do not use to free resources. Called
+          under the port mutex to serialize against activate/shutdowns */
        void (*shutdown)(struct tty_port *port);
        void (*drop)(struct tty_port *port);
+       /* Called under the port mutex from tty_port_open, serialized using
+          the port mutex */
+        /* FIXME: long term getting the tty argument *out* of this would be
+           good for consoles */
+       int (*activate)(struct tty_port *port, struct tty_struct *tty);
+       /* Called on the final put of a port */
+       void (*destruct)(struct tty_port *port);
 };
        
 struct tty_port {
@@ -206,12 +214,14 @@ struct tty_port {
        wait_queue_head_t       delta_msr_wait; /* Modem status change */
        unsigned long           flags;          /* TTY flags ASY_*/
        struct mutex            mutex;          /* Locking */
+       struct mutex            buf_mutex;      /* Buffer alloc lock */
        unsigned char           *xmit_buf;      /* Optional buffer */
        unsigned int            close_delay;    /* Close port delay */
        unsigned int            closing_wait;   /* Delay for output */
        int                     drain_delay;    /* Set to zero if no pure time
                                                   based drain is needed else
                                                   set to size of fifo */
+       struct kref             kref;           /* Ref counter */
 };
 
 /*
@@ -439,7 +449,7 @@ extern void initialize_tty_struct(struct tty_struct *tty,
                struct tty_driver *driver, int idx);
 extern struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
                                                                int first_ok);
-extern void tty_release_dev(struct file *filp);
+extern int tty_release(struct inode *inode, struct file *filp);
 extern int tty_init_termios(struct tty_struct *tty);
 
 extern struct tty_struct *tty_pair_get_tty(struct tty_struct *tty);
@@ -454,6 +464,15 @@ extern int tty_write_lock(struct tty_struct *tty, int ndelay);
 extern void tty_port_init(struct tty_port *port);
 extern int tty_port_alloc_xmit_buf(struct tty_port *port);
 extern void tty_port_free_xmit_buf(struct tty_port *port);
+extern void tty_port_put(struct tty_port *port);
+
+extern inline struct tty_port *tty_port_get(struct tty_port *port)
+{
+       if (port)
+               kref_get(&port->kref);
+       return port;
+}
+
 extern struct tty_struct *tty_port_tty_get(struct tty_port *port);
 extern void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty);
 extern int tty_port_carrier_raised(struct tty_port *port);
@@ -467,6 +486,8 @@ extern int tty_port_close_start(struct tty_port *port,
 extern void tty_port_close_end(struct tty_port *port, struct tty_struct *tty);
 extern void tty_port_close(struct tty_port *port,
                                struct tty_struct *tty, struct file *filp);
+extern int tty_port_open(struct tty_port *port,
+                               struct tty_struct *tty, struct file *filp);
 extern inline int tty_port_users(struct tty_port *port)
 {
        return port->count + port->blocked_open;
index ce911ebf91e82c54c65cc2f46d428ed4c1bcab6a..acf6e457c04b17c695b701febae74415812c5671 100644 (file)
@@ -39,8 +39,6 @@ enum port_dev_state {
  * @serial: pointer back to the struct usb_serial owner of this port.
  * @port: pointer to the corresponding tty_port for this port.
  * @lock: spinlock to grab when updating portions of this structure.
- * @mutex: mutex used to synchronize serial_open() and serial_close()
- *     access for this port.
  * @number: the number of the port (the minor number).
  * @interrupt_in_buffer: pointer to the interrupt in buffer for this port.
  * @interrupt_in_urb: pointer to the interrupt in struct urb for this port.
@@ -77,7 +75,6 @@ struct usb_serial_port {
        struct usb_serial       *serial;
        struct tty_port         port;
        spinlock_t              lock;
-       struct mutex            mutex;
        unsigned char           number;
 
        unsigned char           *interrupt_in_buffer;
index 1143012951e98433c9bed5011d6f87ebe32d9bbd..6f50ef55a6f39221cd66aff3c44c476cd5a2cf3b 100644 (file)
@@ -971,7 +971,7 @@ NORET_TYPE void do_exit(long code)
        exit_thread();
        cgroup_exit(tsk, 1);
 
-       if (group_dead && tsk->signal->leader)
+       if (group_dead)
                disassociate_ctty(1);
 
        module_put(task_thread_info(tsk)->exec_domain->module);