浏览代码

Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty-2.6

* 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
  ...
Linus Torvalds 15 年之前
父节点
当前提交
0f4974c439

+ 0 - 154
Documentation/serial/hayes-esp.txt

@@ -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>

+ 7 - 2
Documentation/serial/tty.txt

@@ -42,7 +42,8 @@ TTY side interfaces:
 open()		-	Called when the line discipline is attached to
 open()		-	Called when the line discipline is attached to
 			the terminal. No other call into the line
 			the terminal. No other call into the line
 			discipline for this tty will occur until it
 			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
 close()		-	This is called on a terminal when the line
 			discipline is being unplugged. At the point of
 			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.
 hangup()	-	Called when the tty line is hung up.
 			The line discipline should cease I/O to the tty.
 			The line discipline should cease I/O to the tty.
 			No further calls into the ldisc code will occur.
 			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
 write()		-	A process is writing data through the line
 			discipline.  Multiple write calls are serialized
 			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
 			that might be for the ldisc. Multiple ioctl calls
 			may occur in parallel. May sleep. 
 			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:
 Driver Side Interfaces:
 
 
 receive_buf()	-	Hand buffers of bytes from the driver to the ldisc
 receive_buf()	-	Hand buffers of bytes from the driver to the ldisc

+ 1 - 1
arch/xtensa/platforms/iss/console.c

@@ -196,7 +196,7 @@ static const struct file_operations rs_proc_fops = {
 	.release	= single_release,
 	.release	= single_release,
 };
 };
 
 
-static struct tty_operations serial_ops = {
+static const struct tty_operations serial_ops = {
 	.open = rs_open,
 	.open = rs_open,
 	.close = rs_close,
 	.close = rs_close,
 	.write = rs_write,
 	.write = rs_write,

+ 0 - 13
drivers/char/Kconfig

@@ -201,19 +201,6 @@ config DIGIEPCA
 	  To compile this driver as a module, choose M here: the
 	  To compile this driver as a module, choose M here: the
 	  module will be called epca.
 	  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
 config MOXA_INTELLIO
 	tristate "Moxa Intellio support"
 	tristate "Moxa Intellio support"
 	depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI)
 	depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI)

+ 0 - 1
drivers/char/Makefile

@@ -18,7 +18,6 @@ obj-$(CONFIG_CONSOLE_TRANSLATIONS) += consolemap.o consolemap_deftbl.o
 obj-$(CONFIG_HW_CONSOLE)	+= vt.o defkeymap.o
 obj-$(CONFIG_HW_CONSOLE)	+= vt.o defkeymap.o
 obj-$(CONFIG_AUDIT)		+= tty_audit.o
 obj-$(CONFIG_AUDIT)		+= tty_audit.o
 obj-$(CONFIG_MAGIC_SYSRQ)	+= sysrq.o
 obj-$(CONFIG_MAGIC_SYSRQ)	+= sysrq.o
-obj-$(CONFIG_ESPSERIAL)		+= esp.o
 obj-$(CONFIG_MVME147_SCC)	+= generic_serial.o vme_scc.o
 obj-$(CONFIG_MVME147_SCC)	+= generic_serial.o vme_scc.o
 obj-$(CONFIG_MVME162_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
 obj-$(CONFIG_BVME6000_SCC)	+= generic_serial.o vme_scc.o

+ 1 - 1
drivers/char/bfin_jtag_comm.c

@@ -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,
 	.open            = bfin_jc_open,
 	.close           = bfin_jc_close,
 	.close           = bfin_jc_close,
 	.write           = bfin_jc_write,
 	.write           = bfin_jc_write,

+ 1 - 1
drivers/char/epca.c

@@ -935,7 +935,7 @@ static int info_open(struct tty_struct *tty, struct file *filp)
 	return 0;
 	return 0;
 }
 }
 
 
-static struct tty_operations info_ops = {
+static const struct tty_operations info_ops = {
 	.open = info_open,
 	.open = info_open,
 	.ioctl = info_ioctl,
 	.ioctl = info_ioctl,
 };
 };

+ 0 - 2533
drivers/char/esp.c

@@ -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);

+ 25 - 90
drivers/char/isicom.c

@@ -793,35 +793,30 @@ static inline void isicom_setup_board(struct isi_board *bp)
 {
 {
 	int channel;
 	int channel;
 	struct isi_port *port;
 	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;
 	struct isi_board *card = port->card;
 	unsigned long flags;
 	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;
 		return -ENOMEM;
 
 
 	spin_lock_irqsave(&card->card_lock, flags);
 	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;
 	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);
 		outw(((ISICOM_KILLTX | ISICOM_KILLRX) << 8) | 0x06, card->base);
 		InterruptTheCard(card->base);
 		InterruptTheCard(card->base);
 	}
 	}
-
 	isicom_config_port(tty);
 	isicom_config_port(tty);
-	port->port.flags |= ASYNC_INITIALIZED;
 	spin_unlock_irqrestore(&card->card_lock, flags);
 	spin_unlock_irqrestore(&card->card_lock, flags);
 
 
 	return 0;
 	return 0;
@@ -871,85 +864,37 @@ static struct tty_port *isicom_find_port(struct tty_struct *tty)
 
 
 	return &port->port;
 	return &port->port;
 }
 }
-	
+
 static int isicom_open(struct tty_struct *tty, struct file *filp)
 static int isicom_open(struct tty_struct *tty, struct file *filp)
 {
 {
 	struct isi_port *port;
 	struct isi_port *port;
 	struct isi_board *card;
 	struct isi_board *card;
 	struct tty_port *tport;
 	struct tty_port *tport;
-	int error = 0;
 
 
 	tport = isicom_find_port(tty);
 	tport = isicom_find_port(tty);
 	if (tport == NULL)
 	if (tport == NULL)
 		return -ENODEV;
 		return -ENODEV;
 	port = container_of(tport, struct isi_port, port);
 	port = container_of(tport, struct isi_port, port);
 	card = &isi_card[BOARD(tty->index)];
 	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 */
 /* 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 */
 /* card->lock HAS to be held */
 static void isicom_shutdown_port(struct isi_port *port)
 static void isicom_shutdown_port(struct isi_port *port)
 {
 {
 	struct isi_board *card = port->card;
 	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) {
 	if (--card->count < 0) {
 		pr_dbg("isicom_shutdown_port: bad board(0x%lx) count %d.\n",
 		pr_dbg("isicom_shutdown_port: bad board(0x%lx) count %d.\n",
 			card->base, card->count);
 			card->base, card->count);
 		card->count = 0;
 		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)
 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);
 	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_port *ip = container_of(port, struct isi_port, port);
 	struct isi_board *card = ip->card;
 	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
 	/* indicate to the card that no more data can be received
 	   on this port */
 	   on this port */
 	spin_lock_irqsave(&card->card_lock, flags);
 	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);
 	isicom_shutdown_port(ip);
 	spin_unlock_irqrestore(&card->card_lock, flags);
 	spin_unlock_irqrestore(&card->card_lock, flags);
+	tty_port_free_xmit_buf(port);
 }
 }
 
 
 static void isicom_close(struct tty_struct *tty, struct file *filp)
 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;
 	struct tty_port *port = &ip->port;
 	if (isicom_paranoia_check(ip, tty->name, "isicom_close"))
 	if (isicom_paranoia_check(ip, tty->name, "isicom_close"))
 		return;
 		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 */
 /* write et all */
@@ -1326,15 +1265,9 @@ static void isicom_start(struct tty_struct *tty)
 static void isicom_hangup(struct tty_struct *tty)
 static void isicom_hangup(struct tty_struct *tty)
 {
 {
 	struct isi_port *port = tty->driver_data;
 	struct isi_port *port = tty->driver_data;
-	unsigned long flags;
 
 
 	if (isicom_paranoia_check(port, tty->name, "isicom_hangup"))
 	if (isicom_paranoia_check(port, tty->name, "isicom_hangup"))
 		return;
 		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);
 	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 = {
 static const struct tty_port_operations isicom_port_ops = {
 	.carrier_raised		= isicom_carrier_raised,
 	.carrier_raised		= isicom_carrier_raised,
 	.dtr_rts		= isicom_dtr_rts,
 	.dtr_rts		= isicom_dtr_rts,
+	.activate		= isicom_activate,
+	.shutdown		= isicom_shutdown,
 };
 };
 
 
 static int __devinit reset_card(struct pci_dev *pdev,
 static int __devinit reset_card(struct pci_dev *pdev,

+ 64 - 121
drivers/char/istallion.c

@@ -213,7 +213,6 @@ static int		stli_shared;
  *	with the slave. Most of them need to be updated atomically, so always
  *	with the slave. Most of them need to be updated atomically, so always
  *	use the bit setting operations (unless protected by cli/sti).
  *	use the bit setting operations (unless protected by cli/sti).
  */
  */
-#define	ST_INITIALIZING	1
 #define	ST_OPENING	2
 #define	ST_OPENING	2
 #define	ST_CLOSING	3
 #define	ST_CLOSING	3
 #define	ST_CMDING	4
 #define	ST_CMDING	4
@@ -621,7 +620,7 @@ static int	stli_brdinit(struct stlibrd *brdp);
 static int	stli_startbrd(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_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 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_brdpoll(struct stlibrd *brdp, cdkhdr_t __iomem *hdrp);
 static void	stli_poll(unsigned long arg);
 static void	stli_poll(unsigned long arg);
 static int	stli_hostcmd(struct stlibrd *brdp, struct stliport *portp);
 static int	stli_hostcmd(struct stlibrd *brdp, struct stliport *portp);
@@ -704,7 +703,7 @@ static const struct file_operations	stli_fsiomem = {
 	.owner		= THIS_MODULE,
 	.owner		= THIS_MODULE,
 	.read		= stli_memread,
 	.read		= stli_memread,
 	.write		= stli_memwrite,
 	.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)
 static int stli_open(struct tty_struct *tty, struct file *filp)
 {
 {
 	struct stlibrd *brdp;
 	struct stlibrd *brdp;
 	struct stliport *portp;
 	struct stliport *portp;
-	struct tty_port *port;
 	unsigned int minordev, brdnr, portnr;
 	unsigned int minordev, brdnr, portnr;
-	int rc;
 
 
 	minordev = tty->index;
 	minordev = tty->index;
 	brdnr = MINOR2BRD(minordev);
 	brdnr = MINOR2BRD(minordev);
@@ -809,95 +827,56 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
 		return -ENODEV;
 		return -ENODEV;
 	if (portp->devnr < 1)
 	if (portp->devnr < 1)
 		return -ENODEV;
 		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 stlibrd *brdp;
-	struct stliport *portp;
-	struct tty_port *port;
+	unsigned long ftype;
 	unsigned long flags;
 	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;
 		return;
-	port = &portp->port;
-
-	if (tty_port_close_start(port, tty, filp) == 0)
+	brdp = stli_brds[portp->brdnr];
+	if (brdp == NULL)
 		return;
 		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_TXBUSY, &portp->state);
 	clear_bit(ST_RXSTOP, &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
  *	Hangup this port. This is pretty much like closing the port, only
  *	a little more brutal. No waiting for data to drain. Shutdown the
  *	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)
 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.
  *	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;
 	struct stlibrd *brdp;
 	int brdnr, rc, done;
 	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
  *	Now handle the board specific ioctls. These all depend on the
  *	minor number of the device they were called from.
  *	minor number of the device they were called from.
  */
  */
-	brdnr = iminor(ip);
+	brdnr = iminor(fp->f_dentry->d_inode);
 	if (brdnr >= STL_MAXBRDS)
 	if (brdnr >= STL_MAXBRDS)
 		return -ENODEV;
 		return -ENODEV;
 	brdp = stli_brds[brdnr];
 	brdp = stli_brds[brdnr];
@@ -4420,6 +4361,8 @@ static const struct tty_operations stli_ops = {
 static const struct tty_port_operations stli_port_ops = {
 static const struct tty_port_operations stli_port_ops = {
 	.carrier_raised = stli_carrier_raised,
 	.carrier_raised = stli_carrier_raised,
 	.dtr_rts = stli_dtr_rts,
 	.dtr_rts = stli_dtr_rts,
+	.activate = stli_activate,
+	.shutdown = stli_shutdown,
 };
 };
 
 
 /*****************************************************************************/
 /*****************************************************************************/

+ 83 - 206
drivers/char/moxa.c

@@ -34,7 +34,6 @@
 #include <linux/tty.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
 #include <linux/tty_flip.h>
 #include <linux/major.h>
 #include <linux/major.h>
-#include <linux/smp_lock.h>
 #include <linux/string.h>
 #include <linux/string.h>
 #include <linux/fcntl.h>
 #include <linux/fcntl.h>
 #include <linux/ptrace.h>
 #include <linux/ptrace.h>
@@ -139,7 +138,7 @@ struct moxa_port {
 	int cflag;
 	int cflag;
 	unsigned long statusflags;
 	unsigned long statusflags;
 
 
-	u8 DCDState;
+	u8 DCDState;		/* Protected by the port lock */
 	u8 lineCtrl;
 	u8 lineCtrl;
 	u8 lowChkFlag;
 	u8 lowChkFlag;
 };
 };
@@ -151,10 +150,9 @@ struct mon_str {
 };
 };
 
 
 /* statusflags */
 /* 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
 #define SERIAL_DO_RESTART
 
 
@@ -165,6 +163,7 @@ static struct mon_str moxaLog;
 static unsigned int moxaFuncTout = HZ / 2;
 static unsigned int moxaFuncTout = HZ / 2;
 static unsigned int moxaLowWaterChk;
 static unsigned int moxaLowWaterChk;
 static DEFINE_MUTEX(moxa_openlock);
 static DEFINE_MUTEX(moxa_openlock);
+static DEFINE_SPINLOCK(moxa_lock);
 /* Variables for insmod */
 /* Variables for insmod */
 #ifdef MODULE
 #ifdef MODULE
 static unsigned long baseaddr[MAX_BOARDS];
 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 int moxa_write_room(struct tty_struct *);
 static void moxa_flush_buffer(struct tty_struct *);
 static void moxa_flush_buffer(struct tty_struct *);
 static int moxa_chars_in_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_set_termios(struct tty_struct *, struct ktermios *);
 static void moxa_stop(struct tty_struct *);
 static void moxa_stop(struct tty_struct *);
 static void moxa_start(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);
 			 unsigned int set, unsigned int clear);
 static void moxa_poll(unsigned long);
 static void moxa_poll(unsigned long);
 static void moxa_set_tty_param(struct tty_struct *, struct ktermios *);
 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 int moxa_carrier_raised(struct tty_port *);
+static void moxa_dtr_rts(struct tty_port *, int);
 /*
 /*
  * moxa board interface functions:
  * moxa board interface functions:
  */
  */
@@ -234,6 +231,8 @@ static void MoxaSetFifo(struct moxa_port *port, int enable);
  * I/O functions
  * I/O functions
  */
  */
 
 
+static DEFINE_SPINLOCK(moxafunc_lock);
+
 static void moxa_wait_finish(void __iomem *ofsAddr)
 static void moxa_wait_finish(void __iomem *ofsAddr)
 {
 {
 	unsigned long end = jiffies + moxaFuncTout;
 	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)
 static void moxafunc(void __iomem *ofsAddr, u16 cmd, u16 arg)
 {
 {
+        unsigned long flags;
+        spin_lock_irqsave(&moxafunc_lock, flags);
 	writew(arg, ofsAddr + FuncArg);
 	writew(arg, ofsAddr + FuncArg);
 	writew(cmd, ofsAddr + FuncCode);
 	writew(cmd, ofsAddr + FuncCode);
 	moxa_wait_finish(ofsAddr);
 	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)
 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;
 		struct moxa_port *p;
 		unsigned int i, j;
 		unsigned int i, j;
 
 
-		mutex_lock(&moxa_openlock);
 		for (i = 0; i < MAX_BOARDS; i++) {
 		for (i = 0; i < MAX_BOARDS; i++) {
 			p = moxa_boards[i].ports;
 			p = moxa_boards[i].ports;
 			for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) {
 			for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) {
 				memset(&tmp, 0, sizeof(tmp));
 				memset(&tmp, 0, sizeof(tmp));
+				spin_lock_bh(&moxa_lock);
 				if (moxa_boards[i].ready) {
 				if (moxa_boards[i].ready) {
 					tmp.inq = MoxaPortRxQueue(p);
 					tmp.inq = MoxaPortRxQueue(p);
 					tmp.outq = MoxaPortTxQueue(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;
 					return -EFAULT;
-				}
 			}
 			}
 		}
 		}
-		mutex_unlock(&moxa_openlock);
 		break;
 		break;
 	} case MOXA_GET_OQUEUE:
 	} case MOXA_GET_OQUEUE:
 		status = MoxaPortTxQueue(ch);
 		status = MoxaPortTxQueue(ch);
@@ -330,16 +343,20 @@ static int moxa_ioctl(struct tty_struct *tty, struct file *file,
 		struct moxa_port *p;
 		struct moxa_port *p;
 		unsigned int i, j;
 		unsigned int i, j;
 
 
-		mutex_lock(&moxa_openlock);
 		for (i = 0; i < MAX_BOARDS; i++) {
 		for (i = 0; i < MAX_BOARDS; i++) {
 			p = moxa_boards[i].ports;
 			p = moxa_boards[i].ports;
 			for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) {
 			for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) {
 				struct tty_struct *ttyp;
 				struct tty_struct *ttyp;
 				memset(&tmp, 0, sizeof(tmp));
 				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;
 					goto copy;
+                                }
 
 
 				status = MoxaPortLineStatus(p);
 				status = MoxaPortLineStatus(p);
+				spin_unlock_bh(&moxa_lock);
+
 				if (status & 1)
 				if (status & 1)
 					tmp.cts = 1;
 					tmp.cts = 1;
 				if (status & 2)
 				if (status & 2)
@@ -354,24 +371,21 @@ static int moxa_ioctl(struct tty_struct *tty, struct file *file,
 					tmp.cflag = ttyp->termios->c_cflag;
 					tmp.cflag = ttyp->termios->c_cflag;
 				tty_kref_put(tty);
 				tty_kref_put(tty);
 copy:
 copy:
-				if (copy_to_user(argm, &tmp, sizeof(tmp))) {
-					mutex_unlock(&moxa_openlock);
+				if (copy_to_user(argm, &tmp, sizeof(tmp)))
 					return -EFAULT;
 					return -EFAULT;
-				}
 			}
 			}
 		}
 		}
-		mutex_unlock(&moxa_openlock);
 		break;
 		break;
 	}
 	}
 	case TIOCGSERIAL:
 	case TIOCGSERIAL:
-		mutex_lock(&moxa_openlock);
+	        mutex_lock(&ch->port.mutex);
 		ret = moxa_get_serial_info(ch, argp);
 		ret = moxa_get_serial_info(ch, argp);
-		mutex_unlock(&moxa_openlock);
+		mutex_unlock(&ch->port.mutex);
 		break;
 		break;
 	case TIOCSSERIAL:
 	case TIOCSSERIAL:
-		mutex_lock(&moxa_openlock);
+	        mutex_lock(&ch->port.mutex);
 		ret = moxa_set_serial_info(ch, argp);
 		ret = moxa_set_serial_info(ch, argp);
-		mutex_unlock(&moxa_openlock);
+		mutex_unlock(&ch->port.mutex);
 		break;
 		break;
 	default:
 	default:
 		ret = -ENOIOCTLCMD;
 		ret = -ENOIOCTLCMD;
@@ -396,8 +410,6 @@ static const struct tty_operations moxa_ops = {
 	.flush_buffer = moxa_flush_buffer,
 	.flush_buffer = moxa_flush_buffer,
 	.chars_in_buffer = moxa_chars_in_buffer,
 	.chars_in_buffer = moxa_chars_in_buffer,
 	.ioctl = moxa_ioctl,
 	.ioctl = moxa_ioctl,
-	.throttle = moxa_throttle,
-	.unthrottle = moxa_unthrottle,
 	.set_termios = moxa_set_termios,
 	.set_termios = moxa_set_termios,
 	.stop = moxa_stop,
 	.stop = moxa_stop,
 	.start = moxa_start,
 	.start = moxa_start,
@@ -409,11 +421,12 @@ static const struct tty_operations moxa_ops = {
 
 
 static const struct tty_port_operations moxa_port_ops = {
 static const struct tty_port_operations moxa_port_ops = {
 	.carrier_raised = moxa_carrier_raised,
 	.carrier_raised = moxa_carrier_raised,
+	.dtr_rts = moxa_dtr_rts,
+	.shutdown = moxa_shutdown,
 };
 };
 
 
 static struct tty_driver *moxaDriver;
 static struct tty_driver *moxaDriver;
 static DEFINE_TIMER(moxaTimer, moxa_poll, 0, 0);
 static DEFINE_TIMER(moxaTimer, moxa_poll, 0, 0);
-static DEFINE_SPINLOCK(moxa_lock);
 
 
 /*
 /*
  * HW init
  * HW init
@@ -1112,14 +1125,12 @@ static void __exit moxa_exit(void)
 module_init(moxa_init);
 module_init(moxa_init);
 module_exit(moxa_exit);
 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);
 	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)
 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);
 	struct moxa_port *ch = container_of(port, struct moxa_port, port);
 	int dcd;
 	int dcd;
 
 
-	spin_lock_bh(&moxa_lock);
+	spin_lock_irq(&port->lock);
 	dcd = ch->DCDState;
 	dcd = ch->DCDState;
-	spin_unlock_bh(&moxa_lock);
+	spin_unlock_irq(&port->lock);
 	return dcd;
 	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)
 static int moxa_open(struct tty_struct *tty, struct file *filp)
 {
 {
 	struct moxa_board_conf *brd;
 	struct moxa_board_conf *brd;
@@ -1194,6 +1179,7 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
 	ch->port.count++;
 	ch->port.count++;
 	tty->driver_data = ch;
 	tty->driver_data = ch;
 	tty_port_tty_set(&ch->port, tty);
 	tty_port_tty_set(&ch->port, tty);
+	mutex_lock(&ch->port.mutex);
 	if (!(ch->port.flags & ASYNC_INITIALIZED)) {
 	if (!(ch->port.flags & ASYNC_INITIALIZED)) {
 		ch->statusflags = 0;
 		ch->statusflags = 0;
 		moxa_set_tty_param(tty, tty->termios);
 		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);
 		MoxaSetFifo(ch, ch->type == PORT_16550A);
 		ch->port.flags |= ASYNC_INITIALIZED;
 		ch->port.flags |= ASYNC_INITIALIZED;
 	}
 	}
+	mutex_unlock(&ch->port.mutex);
 	mutex_unlock(&moxa_openlock);
 	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;
 	return retval;
 }
 }
 
 
 static void moxa_close(struct tty_struct *tty, struct file *filp)
 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;
 	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,
 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);
 	len = MoxaPortWriteData(tty, buf, count);
 	spin_unlock_bh(&moxa_lock);
 	spin_unlock_bh(&moxa_lock);
 
 
-	ch->statusflags |= LOWWAIT;
+	set_bit(LOWWAIT, &ch->statusflags);
 	return len;
 	return len;
 }
 }
 
 
@@ -1300,40 +1248,21 @@ static int moxa_chars_in_buffer(struct tty_struct *tty)
 	struct moxa_port *ch = tty->driver_data;
 	struct moxa_port *ch = tty->driver_data;
 	int chars;
 	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);
 	chars = MoxaPortTxQueue(ch);
-	if (chars) {
+	if (chars)
 		/*
 		/*
 		 * Make it possible to wakeup anything waiting for output
 		 * Make it possible to wakeup anything waiting for output
 		 * in tty_ioctl.c, etc.
 		 * in tty_ioctl.c, etc.
 		 */
 		 */
-		if (!(ch->statusflags & EMPTYWAIT))
-			moxa_setup_empty_event(tty);
-	}
-	unlock_kernel();
+        	set_bit(EMPTYWAIT, &ch->statusflags);
 	return chars;
 	return chars;
 }
 }
 
 
 static int moxa_tiocmget(struct tty_struct *tty, struct file *file)
 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;
 	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);
 	MoxaPortGetLineOut(ch, &dtr, &rts);
 	if (dtr)
 	if (dtr)
 		flag |= TIOCM_DTR;
 		flag |= TIOCM_DTR;
@@ -1346,7 +1275,6 @@ static int moxa_tiocmget(struct tty_struct *tty, struct file *file)
 		flag |= TIOCM_DSR;
 		flag |= TIOCM_DSR;
 	if (dtr & 4)
 	if (dtr & 4)
 		flag |= TIOCM_CD;
 		flag |= TIOCM_CD;
-	mutex_unlock(&moxa_openlock);
 	return flag;
 	return flag;
 }
 }
 
 
@@ -1379,20 +1307,6 @@ static int moxa_tiocmset(struct tty_struct *tty, struct file *file,
 	return 0;
 	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,
 static void moxa_set_termios(struct tty_struct *tty,
 		struct ktermios *old_termios)
 		struct ktermios *old_termios)
 {
 {
@@ -1412,7 +1326,7 @@ static void moxa_stop(struct tty_struct *tty)
 	if (ch == NULL)
 	if (ch == NULL)
 		return;
 		return;
 	MoxaPortTxDisable(ch);
 	MoxaPortTxDisable(ch);
-	ch->statusflags |= TXSTOPPED;
+	set_bit(TXSTOPPED, &ch->statusflags);
 }
 }
 
 
 
 
@@ -1427,38 +1341,32 @@ static void moxa_start(struct tty_struct *tty)
 		return;
 		return;
 
 
 	MoxaPortTxEnable(ch);
 	MoxaPortTxEnable(ch);
-	ch->statusflags &= ~TXSTOPPED;
+	clear_bit(TXSTOPPED, &ch->statusflags);
 }
 }
 
 
 static void moxa_hangup(struct tty_struct *tty)
 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)
 static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd)
 {
 {
 	struct tty_struct *tty;
 	struct tty_struct *tty;
+	unsigned long flags;
 	dcd = !!dcd;
 	dcd = !!dcd;
 
 
+	spin_lock_irqsave(&p->port.lock, flags);
 	if (dcd != p->DCDState) {
 	if (dcd != p->DCDState) {
+        	p->DCDState = dcd;
+        	spin_unlock_irqrestore(&p->port.lock, flags);
 		tty = tty_port_tty_get(&p->port);
 		tty = tty_port_tty_get(&p->port);
 		if (tty && C_CLOCAL(tty) && !dcd)
 		if (tty && C_CLOCAL(tty) && !dcd)
 			tty_hangup(tty);
 			tty_hangup(tty);
 		tty_kref_put(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,
 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;
 	u16 intr;
 
 
 	if (tty) {
 	if (tty) {
-		if ((p->statusflags & EMPTYWAIT) &&
+		if (test_bit(EMPTYWAIT, &p->statusflags) &&
 				MoxaPortTxQueue(p) == 0) {
 				MoxaPortTxQueue(p) == 0) {
-			p->statusflags &= ~EMPTYWAIT;
+			clear_bit(EMPTYWAIT, &p->statusflags);
 			tty_wakeup(tty);
 			tty_wakeup(tty);
 		}
 		}
-		if ((p->statusflags & LOWWAIT) && !tty->stopped &&
+		if (test_bit(LOWWAIT, &p->statusflags) && !tty->stopped &&
 				MoxaPortTxQueue(p) <= WAKEUP_CHARS) {
 				MoxaPortTxQueue(p) <= WAKEUP_CHARS) {
-			p->statusflags &= ~LOWWAIT;
+			clear_bit(LOWWAIT, &p->statusflags);
 			tty_wakeup(tty);
 			tty_wakeup(tty);
 		}
 		}
 
 
-		if (inited && !(p->statusflags & THROTTLE) &&
+		if (inited && !test_bit(TTY_THROTTLED, &tty->flags) &&
 				MoxaPortRxQueue(p) > 0) { /* RX */
 				MoxaPortRxQueue(p) > 0) { /* RX */
 			MoxaPortReadData(p);
 			MoxaPortReadData(p);
 			tty_schedule_flip(tty);
 			tty_schedule_flip(tty);
 		}
 		}
 	} else {
 	} else {
-		p->statusflags &= ~EMPTYWAIT;
+		clear_bit(EMPTYWAIT, &p->statusflags);
 		MoxaPortFlushData(p, 0); /* flush RX */
 		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);
 	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: 					     *
  *	Driver level functions: 					     *
  *****************************************************************************/
  *****************************************************************************/
@@ -1918,10 +1797,12 @@ static int MoxaPortSetTermio(struct moxa_port *port, struct ktermios *termio,
 	baud = MoxaPortSetBaud(port, baud);
 	baud = MoxaPortSetBaud(port, baud);
 
 
 	if (termio->c_iflag & (IXON | IXOFF | IXANY)) {
 	if (termio->c_iflag & (IXON | IXOFF | IXANY)) {
+	        spin_lock_irq(&moxafunc_lock);
 		writeb(termio->c_cc[VSTART], ofsAddr + FuncArg);
 		writeb(termio->c_cc[VSTART], ofsAddr + FuncArg);
 		writeb(termio->c_cc[VSTOP], ofsAddr + FuncArg1);
 		writeb(termio->c_cc[VSTOP], ofsAddr + FuncArg1);
 		writeb(FC_SetXonXoff, ofsAddr + FuncCode);
 		writeb(FC_SetXonXoff, ofsAddr + FuncCode);
 		moxa_wait_finish(ofsAddr);
 		moxa_wait_finish(ofsAddr);
+		spin_unlock_irq(&moxafunc_lock);
 
 
 	}
 	}
 	return baud;
 	return baud;
@@ -1974,18 +1855,14 @@ static int MoxaPortLineStatus(struct moxa_port *port)
 	int val;
 	int val;
 
 
 	ofsAddr = port->tableAddr;
 	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 = readw(ofsAddr + FlagStat) >> 4;
-	}
 	val &= 0x0B;
 	val &= 0x0B;
 	if (val & 8)
 	if (val & 8)
 		val |= 4;
 		val |= 4;
-	spin_lock_bh(&moxa_lock);
 	moxa_new_dcdstate(port, val & 8);
 	moxa_new_dcdstate(port, val & 8);
-	spin_unlock_bh(&moxa_lock);
 	val &= 7;
 	val &= 7;
 	return val;
 	return val;
 }
 }

+ 109 - 139
drivers/char/mxser.c

@@ -23,7 +23,6 @@
 #include <linux/errno.h>
 #include <linux/errno.h>
 #include <linux/signal.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/sched.h>
-#include <linux/smp_lock.h>
 #include <linux/timer.h>
 #include <linux/timer.h>
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
 #include <linux/tty.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 page;
 	unsigned long flags;
 	unsigned long flags;
 
 
@@ -868,22 +867,13 @@ static int mxser_startup(struct tty_struct *tty)
 
 
 	spin_lock_irqsave(&info->slock, flags);
 	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) {
 	if (!info->ioaddr || !info->type) {
 		set_bit(TTY_IO_ERROR, &tty->flags);
 		set_bit(TTY_IO_ERROR, &tty->flags);
 		free_page(page);
 		free_page(page);
 		spin_unlock_irqrestore(&info->slock, flags);
 		spin_unlock_irqrestore(&info->slock, flags);
 		return 0;
 		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
 	 * 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
 	 * and set the speed of the serial port
 	 */
 	 */
 	mxser_change_speed(tty, NULL);
 	mxser_change_speed(tty, NULL);
-	info->port.flags |= ASYNC_INITIALIZED;
 	spin_unlock_irqrestore(&info->slock, flags);
 	spin_unlock_irqrestore(&info->slock, flags);
 
 
 	return 0;
 	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;
 	unsigned long flags;
 
 
-	if (!(info->port.flags & ASYNC_INITIALIZED))
-		return;
-
 	spin_lock_irqsave(&info->slock, flags);
 	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);
 	wake_up_interruptible(&info->port.delta_msr_wait);
 
 
 	/*
 	/*
-	 * Free the IRQ, if necessary
+	 * Free the xmit buffer, if necessary
 	 */
 	 */
 	if (info->port.xmit_buf) {
 	if (info->port.xmit_buf) {
 		free_page((unsigned long) 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;
 	info->IER = 0;
 	outb(0x00, info->ioaddr + UART_IER);
 	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 */
 	/* clear Rx/Tx FIFO's */
 	if (info->board->chip_flag)
 	if (info->board->chip_flag)
 		outb(UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT |
 		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 */
 	/* read data port to reset things */
 	(void) inb(info->ioaddr + UART_RX);
 	(void) inb(info->ioaddr + UART_RX);
 
 
-	set_bit(TTY_IO_ERROR, &tty->flags);
-
-	info->port.flags &= ~ASYNC_INITIALIZED;
 
 
 	if (info->board->chip_flag)
 	if (info->board->chip_flag)
 		SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(info->ioaddr);
 		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)
 static int mxser_open(struct tty_struct *tty, struct file *filp)
 {
 {
 	struct mxser_port *info;
 	struct mxser_port *info;
-	unsigned long flags;
-	int retval, line;
+	int line;
 
 
 	line = tty->index;
 	line = tty->index;
 	if (line == MXSER_PORTS)
 	if (line == MXSER_PORTS)
@@ -1035,23 +1012,7 @@ static int mxser_open(struct tty_struct *tty, struct file *filp)
 	if (!info->ioaddr)
 	if (!info->ioaddr)
 		return -ENODEV;
 		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)
 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);
 	struct mxser_port *info = container_of(port, struct mxser_port, port);
 	unsigned long timeout;
 	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
 	 * At this point we stop accepting input.  To do this, we
 	 * disable the receive line status interrupts, and tell the
 	 * 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)
 	if (info->board->chip_flag)
 		info->IER &= ~MOXA_MUST_RECV_ISR;
 		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;
 		return;
 	if (tty_port_close_start(port, tty, filp) == 0)
 	if (tty_port_close_start(port, tty, filp) == 0)
 		return;
 		return;
-	mxser_close_port(tty, port);
+	mutex_lock(&port->mutex);
+	mxser_close_port(port);
 	mxser_flush_buffer(tty);
 	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
 	/* Right now the tty_port set is done outside of the close_end helper
 	   as we don't yet have everyone using refcounts */	
 	   as we don't yet have everyone using refcounts */	
 	tty_port_close_end(port, tty);
 	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 serial_struct __user *new_info)
 {
 {
 	struct mxser_port *info = tty->driver_data;
 	struct mxser_port *info = tty->driver_data;
+	struct tty_port *port = &info->port;
 	struct serial_struct new_serial;
 	struct serial_struct new_serial;
 	speed_t baud;
 	speed_t baud;
 	unsigned long sl_flags;
 	unsigned long sl_flags;
@@ -1290,7 +1244,7 @@ static int mxser_set_serial_info(struct tty_struct *tty,
 			new_serial.port != info->ioaddr)
 			new_serial.port != info->ioaddr)
 		return -EINVAL;
 		return -EINVAL;
 
 
-	flags = info->port.flags & ASYNC_SPD_MASK;
+	flags = port->flags & ASYNC_SPD_MASK;
 
 
 	if (!capable(CAP_SYS_ADMIN)) {
 	if (!capable(CAP_SYS_ADMIN)) {
 		if ((new_serial.baud_base != info->baud_base) ||
 		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.
 		 * OK, past this point, all the error checking has been done.
 		 * At this point, we start making changes.....
 		 * 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));
 				(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.baud_base != info->baud_base ||
 				new_serial.custom_divisor !=
 				new_serial.custom_divisor !=
 				info->custom_divisor)) {
 				info->custom_divisor)) {
+			if (new_serial.custom_divisor == 0)
+				return -EINVAL;
 			baud = new_serial.baud_base / new_serial.custom_divisor;
 			baud = new_serial.baud_base / new_serial.custom_divisor;
 			tty_encode_baud_rate(tty, baud, baud);
 			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);
 	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);
 			spin_lock_irqsave(&info->slock, sl_flags);
 			mxser_change_speed(tty, NULL);
 			mxser_change_speed(tty, NULL);
 			spin_unlock_irqrestore(&info->slock, sl_flags);
 			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;
 	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)
 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;
 	struct tty_struct *tty;
 	int result, status;
 	int result, status;
 	unsigned int i, j;
 	unsigned int i, j;
@@ -1536,38 +1494,39 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
 
 
 	case MOXA_CHKPORTENABLE:
 	case MOXA_CHKPORTENABLE:
 		result = 0;
 		result = 0;
-		lock_kernel();
 		for (i = 0; i < MXSER_BOARDS; i++)
 		for (i = 0; i < MXSER_BOARDS; i++)
 			for (j = 0; j < MXSER_PORTS_PER_BOARD; j++)
 			for (j = 0; j < MXSER_PORTS_PER_BOARD; j++)
 				if (mxser_boards[i].ports[j].ioaddr)
 				if (mxser_boards[i].ports[j].ioaddr)
 					result |= (1 << i);
 					result |= (1 << i);
-		unlock_kernel();
 		return put_user(result, (unsigned long __user *)argp);
 		return put_user(result, (unsigned long __user *)argp);
 	case MOXA_GETDATACOUNT:
 	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)))
 		if (copy_to_user(argp, &mxvar_log, sizeof(mxvar_log)))
 			ret = -EFAULT;
 			ret = -EFAULT;
-		unlock_kernel();
 		return ret;
 		return ret;
 	case MOXA_GETMSTATUS: {
 	case MOXA_GETMSTATUS: {
 		struct mxser_mstatus ms, __user *msu = argp;
 		struct mxser_mstatus ms, __user *msu = argp;
-		lock_kernel();
 		for (i = 0; i < MXSER_BOARDS; i++)
 		for (i = 0; i < MXSER_BOARDS; i++)
 			for (j = 0; j < MXSER_PORTS_PER_BOARD; j++) {
 			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));
 				memset(&ms, 0, sizeof(ms));
 
 
-				if (!port->ioaddr)
+				mutex_lock(&port->mutex);
+				if (!ip->ioaddr)
 					goto copy;
 					goto copy;
 				
 				
-				tty = tty_port_tty_get(&port->port);
+				tty = tty_port_tty_get(port);
 
 
 				if (!tty || !tty->termios)
 				if (!tty || !tty->termios)
-					ms.cflag = port->normal_termios.c_cflag;
+					ms.cflag = ip->normal_termios.c_cflag;
 				else
 				else
 					ms.cflag = tty->termios->c_cflag;
 					ms.cflag = tty->termios->c_cflag;
 				tty_kref_put(tty);
 				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)
 				if (status & UART_MSR_DCD)
 					ms.dcd = 1;
 					ms.dcd = 1;
 				if (status & UART_MSR_DSR)
 				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)
 				if (status & UART_MSR_CTS)
 					ms.cts = 1;
 					ms.cts = 1;
 			copy:
 			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;
 					return -EFAULT;
-				}
 				msu++;
 				msu++;
 			}
 			}
-		unlock_kernel();
 		return 0;
 		return 0;
 	}
 	}
 	case MOXA_ASPP_MON_EXT: {
 	case MOXA_ASPP_MON_EXT: {
@@ -1593,41 +1550,48 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
 		if (!me)
 		if (!me)
 			return -ENOMEM;
 			return -ENOMEM;
 
 
-		lock_kernel();
 		for (i = 0, p = 0; i < MXSER_BOARDS; i++) {
 		for (i = 0, p = 0; i < MXSER_BOARDS; i++) {
 			for (j = 0; j < MXSER_PORTS_PER_BOARD; j++, p++) {
 			for (j = 0; j < MXSER_PORTS_PER_BOARD; j++, p++) {
 				if (p >= ARRAY_SIZE(me->rx_cnt)) {
 				if (p >= ARRAY_SIZE(me->rx_cnt)) {
 					i = MXSER_BOARDS;
 					i = MXSER_BOARDS;
 					break;
 					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;
 					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)
 				if (status & UART_MSR_TERI)
-					port->icount.rng++;
+					ip->icount.rng++;
 				if (status & UART_MSR_DDSR)
 				if (status & UART_MSR_DDSR)
-					port->icount.dsr++;
+					ip->icount.dsr++;
 				if (status & UART_MSR_DDCD)
 				if (status & UART_MSR_DDCD)
-					port->icount.dcd++;
+					ip->icount.dcd++;
 				if (status & UART_MSR_DCTS)
 				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] =
 				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) {
 				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 {
 				} else {
 					cflag = tty->termios->c_cflag;
 					cflag = tty->termios->c_cflag;
 					iflag = tty->termios->c_iflag;
 					iflag = tty->termios->c_iflag;
@@ -1646,16 +1610,15 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
 				if (iflag & (IXON | IXOFF))
 				if (iflag & (IXON | IXOFF))
 					me->flowctrl[p] |= 0x0C;
 					me->flowctrl[p] |= 0x0C;
 
 
-				if (port->type == PORT_16550A)
+				if (ip->type == PORT_16550A)
 					me->fifo[p] = 1;
 					me->fifo[p] = 1;
 
 
-				opmode = inb(port->opmode_ioaddr) >>
-						((p % 4) * 2);
+				opmode = inb(ip->opmode_ioaddr)>>((p % 4) * 2);
 				opmode &= OP_MODE_MASK;
 				opmode &= OP_MODE_MASK;
 				me->iftype[p] = opmode;
 				me->iftype[p] = opmode;
+				mutex_unlock(&port->mutex);
 			}
 			}
 		}
 		}
-		unlock_kernel();
 		if (copy_to_user(argp, me, sizeof(*me)))
 		if (copy_to_user(argp, me, sizeof(*me)))
 			ret = -EFAULT;
 			ret = -EFAULT;
 		kfree(me);
 		kfree(me);
@@ -1692,6 +1655,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
 		unsigned int cmd, unsigned long arg)
 		unsigned int cmd, unsigned long arg)
 {
 {
 	struct mxser_port *info = tty->driver_data;
 	struct mxser_port *info = tty->driver_data;
+	struct tty_port *port = &info->port;
 	struct async_icount cnow;
 	struct async_icount cnow;
 	unsigned long flags;
 	unsigned long flags;
 	void __user *argp = (void __user *)arg;
 	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 != RS422_MODE &&
 					opmode != RS485_4WIRE_MODE)
 					opmode != RS485_4WIRE_MODE)
 				return -EFAULT;
 				return -EFAULT;
-			lock_kernel();
 			mask = ModeMask[p];
 			mask = ModeMask[p];
 			shiftbit = p * 2;
 			shiftbit = p * 2;
+			spin_lock_irq(&info->slock);
 			val = inb(info->opmode_ioaddr);
 			val = inb(info->opmode_ioaddr);
 			val &= mask;
 			val &= mask;
 			val |= (opmode << shiftbit);
 			val |= (opmode << shiftbit);
 			outb(val, info->opmode_ioaddr);
 			outb(val, info->opmode_ioaddr);
-			unlock_kernel();
+			spin_unlock_irq(&info->slock);
 		} else {
 		} else {
-			lock_kernel();
 			shiftbit = p * 2;
 			shiftbit = p * 2;
+			spin_lock_irq(&info->slock);
 			opmode = inb(info->opmode_ioaddr) >> shiftbit;
 			opmode = inb(info->opmode_ioaddr) >> shiftbit;
+			spin_unlock_irq(&info->slock);
 			opmode &= OP_MODE_MASK;
 			opmode &= OP_MODE_MASK;
-			unlock_kernel();
 			if (put_user(opmode, (int __user *)argp))
 			if (put_user(opmode, (int __user *)argp))
 				return -EFAULT;
 				return -EFAULT;
 		}
 		}
@@ -1742,14 +1706,14 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
 
 
 	switch (cmd) {
 	switch (cmd) {
 	case TIOCGSERIAL:
 	case TIOCGSERIAL:
-		lock_kernel();
+		mutex_lock(&port->mutex);
 		retval = mxser_get_serial_info(tty, argp);
 		retval = mxser_get_serial_info(tty, argp);
-		unlock_kernel();
+		mutex_unlock(&port->mutex);
 		return retval;
 		return retval;
 	case TIOCSSERIAL:
 	case TIOCSSERIAL:
-		lock_kernel();
+		mutex_lock(&port->mutex);
 		retval = mxser_set_serial_info(tty, argp);
 		retval = mxser_set_serial_info(tty, argp);
-		unlock_kernel();
+		mutex_unlock(&port->mutex);
 		return retval;
 		return retval;
 	case TIOCSERGETLSR:	/* Get line status register */
 	case TIOCSERGETLSR:	/* Get line status register */
 		return  mxser_get_lsr_info(info, argp);
 		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:
 	case MOXA_HighSpeedOn:
 		return put_user(info->baud_base != 115200 ? 1 : 0, (int __user *)argp);
 		return put_user(info->baud_base != 115200 ? 1 : 0, (int __user *)argp);
 	case MOXA_SDS_RSTICOUNTER:
 	case MOXA_SDS_RSTICOUNTER:
-		lock_kernel();
+		spin_lock_irq(&info->slock);
 		info->mon_data.rxcnt = 0;
 		info->mon_data.rxcnt = 0;
 		info->mon_data.txcnt = 0;
 		info->mon_data.txcnt = 0;
-		unlock_kernel();
+		spin_unlock_irq(&info->slock);
 		return 0;
 		return 0;
 
 
 	case MOXA_ASPP_OQUEUE:{
 	case MOXA_ASPP_OQUEUE:{
 		int len, lsr;
 		int len, lsr;
 
 
-		lock_kernel();
 		len = mxser_chars_in_buffer(tty);
 		len = mxser_chars_in_buffer(tty);
+		spin_lock(&info->slock);
 		lsr = inb(info->ioaddr + UART_LSR) & UART_LSR_THRE;
 		lsr = inb(info->ioaddr + UART_LSR) & UART_LSR_THRE;
+		spin_unlock_irq(&info->slock);
 		len += (lsr ? 0 : 1);
 		len += (lsr ? 0 : 1);
-		unlock_kernel();
 
 
 		return put_user(len, (int __user *)argp);
 		return put_user(len, (int __user *)argp);
 	}
 	}
 	case MOXA_ASPP_MON: {
 	case MOXA_ASPP_MON: {
 		int mcr, status;
 		int mcr, status;
 
 
-		lock_kernel();
+		spin_lock(&info->slock);
 		status = mxser_get_msr(info->ioaddr, 1, tty->index);
 		status = mxser_get_msr(info->ioaddr, 1, tty->index);
 		mxser_check_modem_status(tty, info, status);
 		mxser_check_modem_status(tty, info, status);
 
 
 		mcr = inb(info->ioaddr + UART_MCR);
 		mcr = inb(info->ioaddr + UART_MCR);
+		spin_unlock(&info->slock);
+
 		if (mcr & MOXA_MUST_MCR_XON_FLAG)
 		if (mcr & MOXA_MUST_MCR_XON_FLAG)
 			info->mon_data.hold_reason &= ~NPPI_NOTIFY_XOFFHOLD;
 			info->mon_data.hold_reason &= ~NPPI_NOTIFY_XOFFHOLD;
 		else
 		else
@@ -1834,7 +1800,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
 			info->mon_data.hold_reason |= NPPI_NOTIFY_CTSHOLD;
 			info->mon_data.hold_reason |= NPPI_NOTIFY_CTSHOLD;
 		else
 		else
 			info->mon_data.hold_reason &= ~NPPI_NOTIFY_CTSHOLD;
 			info->mon_data.hold_reason &= ~NPPI_NOTIFY_CTSHOLD;
-		unlock_kernel();
+
 		if (copy_to_user(argp, &info->mon_data,
 		if (copy_to_user(argp, &info->mon_data,
 				sizeof(struct mxser_mon)))
 				sizeof(struct mxser_mon)))
 			return -EFAULT;
 			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;
 	struct mxser_port *info = tty->driver_data;
 	unsigned long orig_jiffies, char_time;
 	unsigned long orig_jiffies, char_time;
+	unsigned long flags;
 	int lsr;
 	int lsr;
 
 
 	if (info->type == PORT_UNKNOWN)
 	if (info->type == PORT_UNKNOWN)
@@ -2032,19 +1999,21 @@ static void mxser_wait_until_sent(struct tty_struct *tty, int timeout)
 		timeout, char_time);
 		timeout, char_time);
 	printk("jiff=%lu...", jiffies);
 	printk("jiff=%lu...", jiffies);
 #endif
 #endif
-	lock_kernel();
+	spin_lock_irqsave(&info->slock, flags);
 	while (!((lsr = inb(info->ioaddr + UART_LSR)) & UART_LSR_TEMT)) {
 	while (!((lsr = inb(info->ioaddr + UART_LSR)) & UART_LSR_TEMT)) {
 #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
 #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
 		printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
 		printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
 #endif
 #endif
+		spin_unlock_irqrestore(&info->slock, flags);
 		schedule_timeout_interruptible(char_time);
 		schedule_timeout_interruptible(char_time);
+		spin_lock_irqsave(&info->slock, flags);
 		if (signal_pending(current))
 		if (signal_pending(current))
 			break;
 			break;
 		if (timeout && time_after(jiffies, orig_jiffies + timeout))
 		if (timeout && time_after(jiffies, orig_jiffies + timeout))
 			break;
 			break;
 	}
 	}
+	spin_unlock_irqrestore(&info->slock, flags);
 	set_current_state(TASK_RUNNING);
 	set_current_state(TASK_RUNNING);
-	unlock_kernel();
 
 
 #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
 #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
 	printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
 	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;
 	struct mxser_port *info = tty->driver_data;
 
 
 	mxser_flush_buffer(tty);
 	mxser_flush_buffer(tty);
-	mxser_shutdown(tty);
 	tty_port_hangup(&info->port);
 	tty_port_hangup(&info->port);
 }
 }
 
 
@@ -2363,6 +2331,8 @@ static const struct tty_operations mxser_ops = {
 struct tty_port_operations mxser_port_ops = {
 struct tty_port_operations mxser_port_ops = {
 	.carrier_raised = mxser_carrier_raised,
 	.carrier_raised = mxser_carrier_raised,
 	.dtr_rts = mxser_dtr_rts,
 	.dtr_rts = mxser_dtr_rts,
+	.activate = mxser_activate,
+	.shutdown = mxser_shutdown_port,
 };
 };
 
 
 /*
 /*

+ 1 - 1
drivers/char/pcmcia/ipwireless/tty.c

@@ -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,
 	.open = ipw_open,
 	.close = ipw_close,
 	.close = ipw_close,
 	.hangup = ipw_hangup,
 	.hangup = ipw_hangup,

+ 1 - 1
drivers/char/pty.c

@@ -659,7 +659,7 @@ static int __ptmx_open(struct inode *inode, struct file *filp)
 	if (!retval)
 	if (!retval)
 		return 0;
 		return 0;
 out1:
 out1:
-	tty_release_dev(filp);
+	tty_release(inode, filp);
 	return retval;
 	return retval;
 out:
 out:
 	devpts_kill_index(inode, index);
 	devpts_kill_index(inode, index);

+ 41 - 48
drivers/char/riscom8.c

@@ -793,26 +793,21 @@ static void rc_change_speed(struct tty_struct *tty, struct riscom_board *bp,
 }
 }
 
 
 /* Must be called with interrupts enabled */
 /* 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;
 	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;
 		return -ENOMEM;
 
 
 	spin_lock_irqsave(&riscom_lock, flags);
 	spin_lock_irqsave(&riscom_lock, flags);
 
 
 	clear_bit(TTY_IO_ERROR, &tty->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);
 	spin_unlock_irqrestore(&riscom_lock, flags);
 	return 0;
 	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,
 static void rc_shutdown_port(struct tty_struct *tty,
 			struct riscom_board *bp, struct riscom_port *port)
 			struct riscom_board *bp, struct riscom_port *port)
 {
 {
-	if (!(port->port.flags & ASYNC_INITIALIZED))
-		return;
-
 #ifdef RC_REPORT_OVERRUN
 #ifdef RC_REPORT_OVERRUN
 	printk(KERN_INFO "rc%d: port %d: Total %ld overruns were detected.\n",
 	printk(KERN_INFO "rc%d: port %d: Total %ld overruns were detected.\n",
 	       board_No(bp), port_No(port), port->overrun);
 	       board_No(bp), port_No(port), port->overrun);
@@ -840,11 +832,6 @@ static void rc_shutdown_port(struct tty_struct *tty,
 	}
 	}
 #endif
 #endif
 	tty_port_free_xmit_buf(&port->port);
 	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 */
 	/* Select port */
 	rc_out(bp, CD180_CAR, port_No(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);
 	rc_out(bp, CD180_IER, port->IER);
 
 
 	set_bit(TTY_IO_ERROR, &tty->flags);
 	set_bit(TTY_IO_ERROR, &tty->flags);
-	port->port.flags &= ~ASYNC_INITIALIZED;
 
 
 	if (--bp->count < 0)  {
 	if (--bp->count < 0)  {
 		printk(KERN_INFO "rc%d: rc_shutdown_port: "
 		printk(KERN_INFO "rc%d: rc_shutdown_port: "
@@ -889,6 +875,20 @@ static int carrier_raised(struct tty_port *port)
 	return CD;
 	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)
 static int rc_open(struct tty_struct *tty, struct file *filp)
 {
 {
 	int board;
 	int board;
@@ -909,14 +909,7 @@ static int rc_open(struct tty_struct *tty, struct file *filp)
 	if (error)
 	if (error)
 		return 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)
 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);
 	spin_lock_irqsave(&riscom_lock, flags);
 	rp->IER &= ~IER_RXD;
 	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);
 	rc_shutdown_port(port->tty, bp, rp);
 	spin_unlock_irqrestore(&riscom_lock, flags);
 	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"))
 	if (rc_paranoia_check(port, tty->name, "rc_hangup"))
 		return;
 		return;
 
 
-	rc_shutdown_port(tty, port_Board(port), port);
 	tty_port_hangup(&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 = {
 static const struct tty_port_operations riscom_port_ops = {
 	.carrier_raised = carrier_raised,
 	.carrier_raised = carrier_raised,
+	.dtr_rts = dtr_rts,
 	.shutdown = rc_close_port,
 	.shutdown = rc_close_port,
+	.activate = rc_activate_port,
 };
 };
 
 
 
 

+ 42 - 87
drivers/char/stallion.c

@@ -407,7 +407,7 @@ static unsigned int	stl_baudrates[] = {
  *	Declare all those functions in this driver!
  *	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_brdinit(struct stlbrd *brdp);
 static int	stl_getportstats(struct tty_struct *tty, struct stlport *portp, comstats_t __user *cp);
 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);
 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 = {
 static const struct file_operations	stl_fsiomem = {
 	.owner		= THIS_MODULE,
 	.owner		= THIS_MODULE,
-	.ioctl		= stl_memioctl,
+	.unlocked_ioctl	= stl_memioctl,
 };
 };
 
 
 static struct class *stallion_class;
 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)
 static int stl_open(struct tty_struct *tty, struct file *filp)
 {
 {
 	struct stlport	*portp;
 	struct stlport	*portp;
@@ -737,32 +755,8 @@ static int stl_open(struct tty_struct *tty, struct file *filp)
 	if (portp == NULL)
 	if (portp == NULL)
 		return -ENODEV;
 		return -ENODEV;
 	port = &portp->port;
 	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);
 	stl_disableintrs(portp);
-	if (tty->termios->c_cflag & HUPCL)
-		stl_setsignals(portp, 0, 0);
 	stl_enablerxtx(portp, 0, 0);
 	stl_enablerxtx(portp, 0, 0);
-	stl_flushbuffer(tty);
+	stl_flush(portp);
 	portp->istate = 0;
 	portp->istate = 0;
 	if (portp->tx.buf != NULL) {
 	if (portp->tx.buf != NULL) {
 		kfree(portp->tx.buf);
 		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.head = NULL;
 		portp->tx.tail = 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)
 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);
 	pr_debug("stl_hangup(tty=%p)\n", tty);
 
 
-	portp = tty->driver_data;
 	if (portp == NULL)
 	if (portp == NULL)
 		return;
 		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.
  *	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;
 	int	brdnr, rc;
 	void __user *argp = (void __user *)arg;
 	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)
 	if (brdnr >= STL_MAXBRDS)
 		return -ENODEV;
 		return -ENODEV;
 	rc = 0;
 	rc = 0;
 
 
+	lock_kernel();
 	switch (cmd) {
 	switch (cmd) {
 	case COM_GETPORTSTATS:
 	case COM_GETPORTSTATS:
 		rc = stl_getportstats(NULL, NULL, argp);
 		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;
 		rc = -ENOIOCTLCMD;
 		break;
 		break;
 	}
 	}
-
+	unlock_kernel();
 	return rc;
 	return rc;
 }
 }
 
 
@@ -2549,6 +2502,8 @@ static const struct tty_operations stl_ops = {
 static const struct tty_port_operations stl_port_ops = {
 static const struct tty_port_operations stl_port_ops = {
 	.carrier_raised = stl_carrier_raised,
 	.carrier_raised = stl_carrier_raised,
 	.dtr_rts = stl_dtr_rts,
 	.dtr_rts = stl_dtr_rts,
+	.activate = stl_activate,
+	.shutdown = stl_shutdown,
 };
 };
 
 
 /*****************************************************************************/
 /*****************************************************************************/

+ 86 - 65
drivers/char/tty_io.c

@@ -142,7 +142,6 @@ ssize_t redirected_tty_write(struct file *, const char __user *,
 							size_t, loff_t *);
 							size_t, loff_t *);
 static unsigned int tty_poll(struct file *, poll_table *);
 static unsigned int tty_poll(struct file *, poll_table *);
 static int tty_open(struct inode *, struct file *);
 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);
 long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
 #ifdef CONFIG_COMPAT
 #ifdef CONFIG_COMPAT
 static long tty_compat_ioctl(struct file *file, unsigned int cmd,
 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)
 	if (!tty)
 		return;
 		return;
 
 
-	/* inuse_filps is protected by the single kernel lock */
-	lock_kernel();
 
 
 	spin_lock(&redirect_lock);
 	spin_lock(&redirect_lock);
 	if (redirect && redirect->private_data == tty) {
 	if (redirect && redirect->private_data == tty) {
@@ -516,7 +513,11 @@ static void do_tty_hangup(struct work_struct *work)
 	}
 	}
 	spin_unlock(&redirect_lock);
 	spin_unlock(&redirect_lock);
 
 
+	/* inuse_filps is protected by the single kernel lock */
+	lock_kernel();
 	check_tty_count(tty, "do_tty_hangup");
 	check_tty_count(tty, "do_tty_hangup");
+	unlock_kernel();
+
 	file_list_lock();
 	file_list_lock();
 	/* This breaks for file handles being sent over AF_UNIX sockets ? */
 	/* This breaks for file handles being sent over AF_UNIX sockets ? */
 	list_for_each_entry(filp, &tty->tty_files, f_u.fu_list) {
 	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();
 	file_list_unlock();
 
 
+	lock_kernel();
 	tty_ldisc_hangup(tty);
 	tty_ldisc_hangup(tty);
 
 
 	read_lock(&tasklist_lock);
 	read_lock(&tasklist_lock);
@@ -708,6 +710,8 @@ void disassociate_ctty(int on_exit)
 	struct tty_struct *tty;
 	struct tty_struct *tty;
 	struct pid *tty_pgrp = NULL;
 	struct pid *tty_pgrp = NULL;
 
 
+	if (!current->signal->leader)
+		return;
 
 
 	tty = get_current_tty();
 	tty = get_current_tty();
 	if (tty) {
 	if (tty) {
@@ -773,8 +777,7 @@ void no_tty(void)
 {
 {
 	struct task_struct *tsk = current;
 	struct task_struct *tsk = current;
 	lock_kernel();
 	lock_kernel();
-	if (tsk->signal->leader)
-		disassociate_ctty(0);
+	disassociate_ctty(0);
 	unlock_kernel();
 	unlock_kernel();
 	proc_clear_tty(tsk);
 	proc_clear_tty(tsk);
 }
 }
@@ -1017,14 +1020,16 @@ out:
 
 
 void tty_write_message(struct tty_struct *tty, char *msg)
 void tty_write_message(struct tty_struct *tty, char *msg)
 {
 {
-	lock_kernel();
 	if (tty) {
 	if (tty) {
 		mutex_lock(&tty->atomic_write_lock);
 		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));
 			tty->ops->write(tty, msg, strlen(msg));
+		} else
+			unlock_kernel();
 		tty_write_unlock(tty);
 		tty_write_unlock(tty);
 	}
 	}
-	unlock_kernel();
 	return;
 	return;
 }
 }
 
 
@@ -1202,14 +1207,21 @@ static int tty_driver_install_tty(struct tty_driver *driver,
 						struct tty_struct *tty)
 						struct tty_struct *tty)
 {
 {
 	int idx = tty->index;
 	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) {
 	if (tty_init_termios(tty) == 0) {
+		lock_kernel();
 		tty_driver_kref_get(driver);
 		tty_driver_kref_get(driver);
 		tty->count++;
 		tty->count++;
 		driver->ttys[idx] = tty;
 		driver->ttys[idx] = tty;
+		unlock_kernel();
 		return 0;
 		return 0;
 	}
 	}
 	return -ENOMEM;
 	return -ENOMEM;
@@ -1302,10 +1314,14 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
 	struct tty_struct *tty;
 	struct tty_struct *tty;
 	int retval;
 	int retval;
 
 
+	lock_kernel();
 	/* Check if pty master is being opened multiple times */
 	/* Check if pty master is being opened multiple times */
 	if (driver->subtype == PTY_TYPE_MASTER &&
 	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);
 		return ERR_PTR(-EIO);
+	}
+	unlock_kernel();
 
 
 	/*
 	/*
 	 * First time open is complex, especially for PTY devices.
 	 * 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
 	 * If we fail here just call release_tty to clean up.  No need
 	 * to decrement the use counts, as release_tty doesn't care.
 	 * to decrement the use counts, as release_tty doesn't care.
 	 */
 	 */
-
 	retval = tty_ldisc_setup(tty, tty->link);
 	retval = tty_ldisc_setup(tty, tty->link);
 	if (retval)
 	if (retval)
 		goto release_mem_out;
 		goto release_mem_out;
@@ -1350,7 +1365,9 @@ release_mem_out:
 	if (printk_ratelimit())
 	if (printk_ratelimit())
 		printk(KERN_INFO "tty_init_dev: ldisc open failed, "
 		printk(KERN_INFO "tty_init_dev: ldisc open failed, "
 				 "clearing slot %d\n", idx);
 				 "clearing slot %d\n", idx);
+	lock_kernel();
 	release_tty(tty, idx);
 	release_tty(tty, idx);
+	unlock_kernel();
 	return ERR_PTR(retval);
 	return ERR_PTR(retval);
 }
 }
 
 
@@ -1464,7 +1481,17 @@ static void release_tty(struct tty_struct *tty, int idx)
 	tty_kref_put(tty);
 	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
  * Even releasing the tty structures is a tricky business.. We have
  * to be very careful that the structures are all released at the
  * to be very careful that the structures are all released at the
  * same time, as interrupts might otherwise get the wrong pointers.
  * 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
  * WSH 09/09/97: rewritten to avoid some nasty race conditions that could
  * lead to double frees or releasing memory still in use.
  * 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;
 	struct tty_struct *tty, *o_tty;
 	int	pty_master, tty_closing, o_tty_closing, do_sleep;
 	int	pty_master, tty_closing, o_tty_closing, do_sleep;
 	int	devpts;
 	int	devpts;
 	int	idx;
 	int	idx;
 	char	buf[64];
 	char	buf[64];
-	struct 	inode *inode;
 
 
-	inode = filp->f_path.dentry->d_inode;
 	tty = (struct tty_struct *)filp->private_data;
 	tty = (struct tty_struct *)filp->private_data;
 	if (tty_paranoia_check(tty, inode, "tty_release_dev"))
 	if (tty_paranoia_check(tty, inode, "tty_release_dev"))
-		return;
+		return 0;
 
 
+	lock_kernel();
 	check_tty_count(tty, "tty_release_dev");
 	check_tty_count(tty, "tty_release_dev");
 
 
 	tty_fasync(-1, filp, 0);
 	tty_fasync(-1, filp, 0);
@@ -1500,19 +1527,22 @@ void tty_release_dev(struct file *filp)
 	if (idx < 0 || idx >= tty->driver->num) {
 	if (idx < 0 || idx >= tty->driver->num) {
 		printk(KERN_DEBUG "tty_release_dev: bad idx when trying to "
 		printk(KERN_DEBUG "tty_release_dev: bad idx when trying to "
 				  "free (%s)\n", tty->name);
 				  "free (%s)\n", tty->name);
-		return;
+		unlock_kernel();
+		return 0;
 	}
 	}
 	if (!devpts) {
 	if (!devpts) {
 		if (tty != tty->driver->ttys[idx]) {
 		if (tty != tty->driver->ttys[idx]) {
+			unlock_kernel();
 			printk(KERN_DEBUG "tty_release_dev: driver.table[%d] not tty "
 			printk(KERN_DEBUG "tty_release_dev: driver.table[%d] not tty "
 			       "for (%s)\n", idx, tty->name);
 			       "for (%s)\n", idx, tty->name);
-			return;
+			return 0;
 		}
 		}
 		if (tty->termios != tty->driver->termios[idx]) {
 		if (tty->termios != tty->driver->termios[idx]) {
+			unlock_kernel();
 			printk(KERN_DEBUG "tty_release_dev: driver.termios[%d] not termios "
 			printk(KERN_DEBUG "tty_release_dev: driver.termios[%d] not termios "
 			       "for (%s)\n",
 			       "for (%s)\n",
 			       idx, tty->name);
 			       idx, tty->name);
-			return;
+			return 0;
 		}
 		}
 	}
 	}
 #endif
 #endif
@@ -1526,26 +1556,30 @@ void tty_release_dev(struct file *filp)
 	if (tty->driver->other &&
 	if (tty->driver->other &&
 	     !(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
 	     !(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
 		if (o_tty != tty->driver->other->ttys[idx]) {
 		if (o_tty != tty->driver->other->ttys[idx]) {
+			unlock_kernel();
 			printk(KERN_DEBUG "tty_release_dev: other->table[%d] "
 			printk(KERN_DEBUG "tty_release_dev: other->table[%d] "
 					  "not o_tty for (%s)\n",
 					  "not o_tty for (%s)\n",
 			       idx, tty->name);
 			       idx, tty->name);
-			return;
+			return 0 ;
 		}
 		}
 		if (o_tty->termios != tty->driver->other->termios[idx]) {
 		if (o_tty->termios != tty->driver->other->termios[idx]) {
+			unlock_kernel();
 			printk(KERN_DEBUG "tty_release_dev: other->termios[%d] "
 			printk(KERN_DEBUG "tty_release_dev: other->termios[%d] "
 					  "not o_termios for (%s)\n",
 					  "not o_termios for (%s)\n",
 			       idx, tty->name);
 			       idx, tty->name);
-			return;
+			return 0;
 		}
 		}
 		if (o_tty->link != tty) {
 		if (o_tty->link != tty) {
+			unlock_kernel();
 			printk(KERN_DEBUG "tty_release_dev: bad pty pointers\n");
 			printk(KERN_DEBUG "tty_release_dev: bad pty pointers\n");
-			return;
+			return 0;
 		}
 		}
 	}
 	}
 #endif
 #endif
 	if (tty->ops->close)
 	if (tty->ops->close)
 		tty->ops->close(tty, filp);
 		tty->ops->close(tty, filp);
 
 
+	unlock_kernel();
 	/*
 	/*
 	 * Sanity check: if tty->count is going to zero, there shouldn't be
 	 * 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
 	 * 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 */
 		   opens on /dev/tty */
 
 
 		mutex_lock(&tty_mutex);
 		mutex_lock(&tty_mutex);
+		lock_kernel();
 		tty_closing = tty->count <= 1;
 		tty_closing = tty->count <= 1;
 		o_tty_closing = o_tty &&
 		o_tty_closing = o_tty &&
 			(o_tty->count <= (pty_master ? 1 : 0));
 			(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 "
 		printk(KERN_WARNING "tty_release_dev: %s: read/write wait queue "
 				    "active!\n", tty_name(tty, buf));
 				    "active!\n", tty_name(tty, buf));
+		unlock_kernel();
 		mutex_unlock(&tty_mutex);
 		mutex_unlock(&tty_mutex);
 		schedule();
 		schedule();
 	}
 	}
@@ -1661,8 +1697,10 @@ void tty_release_dev(struct file *filp)
 	mutex_unlock(&tty_mutex);
 	mutex_unlock(&tty_mutex);
 
 
 	/* check whether both sides are closing ... */
 	/* 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
 #ifdef TTY_DEBUG_HANGUP
 	printk(KERN_DEBUG "freeing tty structure...");
 	printk(KERN_DEBUG "freeing tty structure...");
@@ -1680,10 +1718,12 @@ void tty_release_dev(struct file *filp)
 	/* Make this pty number available for reallocation */
 	/* Make this pty number available for reallocation */
 	if (devpts)
 	if (devpts)
 		devpts_kill_index(inode, idx);
 		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
  *	@inode: inode of device file
  *	@filp: file pointer to tty
  *	@filp: file pointer to tty
  *
  *
@@ -1703,7 +1743,7 @@ void tty_release_dev(struct file *filp)
  *		 ->siglock protects ->signal/->sighand
  *		 ->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;
 	struct tty_struct *tty = NULL;
 	int noctty, retval;
 	int noctty, retval;
@@ -1720,10 +1760,12 @@ retry_open:
 	retval = 0;
 	retval = 0;
 
 
 	mutex_lock(&tty_mutex);
 	mutex_lock(&tty_mutex);
+	lock_kernel();
 
 
 	if (device == MKDEV(TTYAUX_MAJOR, 0)) {
 	if (device == MKDEV(TTYAUX_MAJOR, 0)) {
 		tty = get_current_tty();
 		tty = get_current_tty();
 		if (!tty) {
 		if (!tty) {
+			unlock_kernel();
 			mutex_unlock(&tty_mutex);
 			mutex_unlock(&tty_mutex);
 			return -ENXIO;
 			return -ENXIO;
 		}
 		}
@@ -1755,12 +1797,14 @@ retry_open:
 				goto got_driver;
 				goto got_driver;
 			}
 			}
 		}
 		}
+		unlock_kernel();
 		mutex_unlock(&tty_mutex);
 		mutex_unlock(&tty_mutex);
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
 
 
 	driver = get_tty_driver(device, &index);
 	driver = get_tty_driver(device, &index);
 	if (!driver) {
 	if (!driver) {
+		unlock_kernel();
 		mutex_unlock(&tty_mutex);
 		mutex_unlock(&tty_mutex);
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
@@ -1770,6 +1814,7 @@ got_driver:
 		tty = tty_driver_lookup_tty(driver, inode, index);
 		tty = tty_driver_lookup_tty(driver, inode, index);
 
 
 		if (IS_ERR(tty)) {
 		if (IS_ERR(tty)) {
+			unlock_kernel();
 			mutex_unlock(&tty_mutex);
 			mutex_unlock(&tty_mutex);
 			return PTR_ERR(tty);
 			return PTR_ERR(tty);
 		}
 		}
@@ -1784,8 +1829,10 @@ got_driver:
 
 
 	mutex_unlock(&tty_mutex);
 	mutex_unlock(&tty_mutex);
 	tty_driver_kref_put(driver);
 	tty_driver_kref_put(driver);
-	if (IS_ERR(tty))
+	if (IS_ERR(tty)) {
+		unlock_kernel();
 		return PTR_ERR(tty);
 		return PTR_ERR(tty);
+	}
 
 
 	filp->private_data = tty;
 	filp->private_data = tty;
 	file_move(filp, &tty->tty_files);
 	file_move(filp, &tty->tty_files);
@@ -1813,11 +1860,15 @@ got_driver:
 		printk(KERN_DEBUG "error %d in opening %s...", retval,
 		printk(KERN_DEBUG "error %d in opening %s...", retval,
 		       tty->name);
 		       tty->name);
 #endif
 #endif
-		tty_release_dev(filp);
-		if (retval != -ERESTARTSYS)
+		tty_release(inode, filp);
+		if (retval != -ERESTARTSYS) {
+			unlock_kernel();
 			return retval;
 			return retval;
-		if (signal_pending(current))
+		}
+		if (signal_pending(current)) {
+			unlock_kernel();
 			return retval;
 			return retval;
+		}
 		schedule();
 		schedule();
 		/*
 		/*
 		 * Need to reset f_op in case a hangup happened.
 		 * Need to reset f_op in case a hangup happened.
@@ -1826,8 +1877,11 @@ got_driver:
 			filp->f_op = &tty_fops;
 			filp->f_op = &tty_fops;
 		goto retry_open;
 		goto retry_open;
 	}
 	}
+	unlock_kernel();
+
 
 
 	mutex_lock(&tty_mutex);
 	mutex_lock(&tty_mutex);
+	lock_kernel();
 	spin_lock_irq(&current->sighand->siglock);
 	spin_lock_irq(&current->sighand->siglock);
 	if (!noctty &&
 	if (!noctty &&
 	    current->signal->leader &&
 	    current->signal->leader &&
@@ -1835,43 +1889,12 @@ got_driver:
 	    tty->session == NULL)
 	    tty->session == NULL)
 		__proc_set_tty(current, tty);
 		__proc_set_tty(current, tty);
 	spin_unlock_irq(&current->sighand->siglock);
 	spin_unlock_irq(&current->sighand->siglock);
+	unlock_kernel();
 	mutex_unlock(&tty_mutex);
 	mutex_unlock(&tty_mutex);
 	return 0;
 	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
  *	tty_poll	-	check tty status
@@ -2317,9 +2340,7 @@ static int tiocsetd(struct tty_struct *tty, int __user *p)
 	if (get_user(ldisc, p))
 	if (get_user(ldisc, p))
 		return -EFAULT;
 		return -EFAULT;
 
 
-	lock_kernel();
 	ret = tty_set_ldisc(tty, ldisc);
 	ret = tty_set_ldisc(tty, ldisc);
-	unlock_kernel();
 
 
 	return ret;
 	return ret;
 }
 }

+ 21 - 2
drivers/char/tty_ldisc.c

@@ -34,6 +34,8 @@
 #include <linux/vt_kern.h>
 #include <linux/vt_kern.h>
 #include <linux/selection.h>
 #include <linux/selection.h>
 
 
+#include <linux/smp_lock.h>	/* For the moment */
+
 #include <linux/kmod.h>
 #include <linux/kmod.h>
 #include <linux/nsproxy.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)
 static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld)
 {
 {
 	WARN_ON(test_and_set_bit(TTY_LDISC_OPEN, &tty->flags));
 	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;
 	return 0;
 }
 }
 
 
@@ -545,6 +553,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
 	if (IS_ERR(new_ldisc))
 	if (IS_ERR(new_ldisc))
 		return PTR_ERR(new_ldisc);
 		return PTR_ERR(new_ldisc);
 
 
+	lock_kernel();
 	/*
 	/*
 	 *	We need to look at the tty locking here for pty/tty pairs
 	 *	We need to look at the tty locking here for pty/tty pairs
 	 *	when both sides try to change in parallel.
 	 *	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) {
 	if (tty->ldisc->ops->num == ldisc) {
+		unlock_kernel();
 		tty_ldisc_put(new_ldisc);
 		tty_ldisc_put(new_ldisc);
 		return 0;
 		return 0;
 	}
 	}
 
 
+	unlock_kernel();
 	/*
 	/*
 	 *	Problem: What do we do if this blocks ?
 	 *	Problem: What do we do if this blocks ?
 	 *	We could deadlock here
 	 *	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);
 			test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0);
 		mutex_lock(&tty->ldisc_mutex);
 		mutex_lock(&tty->ldisc_mutex);
 	}
 	}
+
+	lock_kernel();
+
 	set_bit(TTY_LDISC_CHANGING, &tty->flags);
 	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;
 	tty->receive_room = 0;
 
 
 	o_ldisc = tty->ldisc;
 	o_ldisc = tty->ldisc;
+
+	unlock_kernel();
 	/*
 	/*
 	 *	Make sure we don't change while someone holds a
 	 *	Make sure we don't change while someone holds a
 	 *	reference to the line discipline. The TTY_LDISC bit
 	 *	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();
 	flush_scheduled_work();
 
 
 	mutex_lock(&tty->ldisc_mutex);
 	mutex_lock(&tty->ldisc_mutex);
+	lock_kernel();
 	if (test_bit(TTY_HUPPED, &tty->flags)) {
 	if (test_bit(TTY_HUPPED, &tty->flags)) {
 		/* We were raced by the hangup method. It will have stomped
 		/* We were raced by the hangup method. It will have stomped
 		   the ldisc data and closed the ldisc down */
 		   the ldisc data and closed the ldisc down */
 		clear_bit(TTY_LDISC_CHANGING, &tty->flags);
 		clear_bit(TTY_LDISC_CHANGING, &tty->flags);
 		mutex_unlock(&tty->ldisc_mutex);
 		mutex_unlock(&tty->ldisc_mutex);
 		tty_ldisc_put(new_ldisc);
 		tty_ldisc_put(new_ldisc);
+		unlock_kernel();
 		return -EIO;
 		return -EIO;
 	}
 	}
 
 
@@ -664,6 +682,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
 	if (o_work)
 	if (o_work)
 		schedule_delayed_work(&o_tty->buf.work, 1);
 		schedule_delayed_work(&o_tty->buf.work, 1);
 	mutex_unlock(&tty->ldisc_mutex);
 	mutex_unlock(&tty->ldisc_mutex);
+	unlock_kernel();
 	return retval;
 	return retval;
 }
 }
 
 

+ 79 - 18
drivers/char/tty_port.c

@@ -25,19 +25,21 @@ void tty_port_init(struct tty_port *port)
 	init_waitqueue_head(&port->close_wait);
 	init_waitqueue_head(&port->close_wait);
 	init_waitqueue_head(&port->delta_msr_wait);
 	init_waitqueue_head(&port->delta_msr_wait);
 	mutex_init(&port->mutex);
 	mutex_init(&port->mutex);
+	mutex_init(&port->buf_mutex);
 	spin_lock_init(&port->lock);
 	spin_lock_init(&port->lock);
 	port->close_delay = (50 * HZ) / 100;
 	port->close_delay = (50 * HZ) / 100;
 	port->closing_wait = (3000 * HZ) / 100;
 	port->closing_wait = (3000 * HZ) / 100;
+	kref_init(&port->kref);
 }
 }
 EXPORT_SYMBOL(tty_port_init);
 EXPORT_SYMBOL(tty_port_init);
 
 
 int tty_port_alloc_xmit_buf(struct tty_port *port)
 int tty_port_alloc_xmit_buf(struct tty_port *port)
 {
 {
 	/* We may sleep in get_zeroed_page() */
 	/* We may sleep in get_zeroed_page() */
-	mutex_lock(&port->mutex);
+	mutex_lock(&port->buf_mutex);
 	if (port->xmit_buf == NULL)
 	if (port->xmit_buf == NULL)
 		port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
 		port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
-	mutex_unlock(&port->mutex);
+	mutex_unlock(&port->buf_mutex);
 	if (port->xmit_buf == NULL)
 	if (port->xmit_buf == NULL)
 		return -ENOMEM;
 		return -ENOMEM;
 	return 0;
 	return 0;
@@ -46,15 +48,32 @@ EXPORT_SYMBOL(tty_port_alloc_xmit_buf);
 
 
 void tty_port_free_xmit_buf(struct tty_port *port)
 void tty_port_free_xmit_buf(struct tty_port *port)
 {
 {
-	mutex_lock(&port->mutex);
+	mutex_lock(&port->buf_mutex);
 	if (port->xmit_buf != NULL) {
 	if (port->xmit_buf != NULL) {
 		free_page((unsigned long)port->xmit_buf);
 		free_page((unsigned long)port->xmit_buf);
 		port->xmit_buf = NULL;
 		port->xmit_buf = NULL;
 	}
 	}
-	mutex_unlock(&port->mutex);
+	mutex_unlock(&port->buf_mutex);
 }
 }
 EXPORT_SYMBOL(tty_port_free_xmit_buf);
 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
  *	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)
 static void tty_port_shutdown(struct tty_port *port)
 {
 {
+	mutex_lock(&port->mutex);
 	if (port->ops->shutdown &&
 	if (port->ops->shutdown &&
 		test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags))
 		test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags))
 			port->ops->shutdown(port);
 			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);
 	spin_lock_irqsave(&port->lock, flags);
 	port->count = 0;
 	port->count = 0;
 	port->flags &= ~ASYNC_NORMAL_ACTIVE;
 	port->flags &= ~ASYNC_NORMAL_ACTIVE;
-	if (port->tty)
+	if (port->tty) {
+		set_bit(TTY_IO_ERROR, &port->tty->flags);
 		tty_kref_put(port->tty);
 		tty_kref_put(port->tty);
+	}
 	port->tty = NULL;
 	port->tty = NULL;
 	spin_unlock_irqrestore(&port->lock, flags);
 	spin_unlock_irqrestore(&port->lock, flags);
 	wake_up_interruptible(&port->open_wait);
 	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
  *	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.
  *	iteration as a hangup may have previously dropped them while we wait.
  */
  */
- 
+
 int tty_port_block_til_ready(struct tty_port *port,
 int tty_port_block_til_ready(struct tty_port *port,
 				struct tty_struct *tty, struct file *filp)
 				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);
 			tty_port_raise_dtr_rts(port);
 
 
 		prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE);
 		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 (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
 			if (port->flags & ASYNC_HUP_NOTIFY)
 			if (port->flags & ASYNC_HUP_NOTIFY)
 				retval = -EAGAIN;
 				retval = -EAGAIN;
@@ -285,11 +308,11 @@ int tty_port_block_til_ready(struct tty_port *port,
 		port->flags |= ASYNC_NORMAL_ACTIVE;
 		port->flags |= ASYNC_NORMAL_ACTIVE;
 	spin_unlock_irqrestore(&port->lock, flags);
 	spin_unlock_irqrestore(&port->lock, flags);
 	return retval;
 	return retval;
-	
 }
 }
 EXPORT_SYMBOL(tty_port_block_til_ready);
 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;
 	unsigned long flags;
 
 
@@ -299,7 +322,7 @@ int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, struct f
 		return 0;
 		return 0;
 	}
 	}
 
 
-	if( tty->count == 1 && port->count != 1) {
+	if (tty->count == 1 && port->count != 1) {
 		printk(KERN_WARNING
 		printk(KERN_WARNING
 		    "tty_port_close_start: tty->count = 1 port count = %d.\n",
 		    "tty_port_close_start: tty->count = 1 port count = %d.\n",
 								port->count);
 								port->count);
@@ -331,12 +354,20 @@ int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, struct f
 		long timeout;
 		long timeout;
 
 
 		if (bps > 1200)
 		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
 		else
 			timeout = 2 * HZ;
 			timeout = 2 * HZ;
 		schedule_timeout_interruptible(timeout);
 		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
 	/* Don't call port->drop for the last reference. Callers will want
 	   to drop the last active reference in ->shutdown() or the tty
 	   to drop the last active reference in ->shutdown() or the tty
 	   shutdown path */
 	   shutdown path */
@@ -348,11 +379,6 @@ void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
 {
 {
 	unsigned long flags;
 	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);
 	spin_lock_irqsave(&port->lock, flags);
 	tty->closing = 0;
 	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)
 	if (tty_port_close_start(port, tty, filp) == 0)
 		return;
 		return;
 	tty_port_shutdown(port);
 	tty_port_shutdown(port);
+	set_bit(TTY_IO_ERROR, &tty->flags);
 	tty_port_close_end(port, tty);
 	tty_port_close_end(port, tty);
 	tty_port_tty_set(port, NULL);
 	tty_port_tty_set(port, NULL);
 }
 }
 EXPORT_SYMBOL(tty_port_close);
 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);

+ 199 - 104
drivers/mmc/card/sdio_uart.c

@@ -29,6 +29,7 @@
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/kernel.h>
+#include <linux/sched.h>
 #include <linux/mutex.h>
 #include <linux/mutex.h>
 #include <linux/seq_file.h>
 #include <linux/seq_file.h>
 #include <linux/serial_reg.h>
 #include <linux/serial_reg.h>
@@ -73,11 +74,10 @@ struct uart_icount {
 };
 };
 
 
 struct sdio_uart_port {
 struct sdio_uart_port {
+	struct tty_port		port;
 	struct kref		kref;
 	struct kref		kref;
 	struct tty_struct	*tty;
 	struct tty_struct	*tty;
 	unsigned int		index;
 	unsigned int		index;
-	unsigned int		opened;
-	struct mutex		open_lock;
 	struct sdio_func	*func;
 	struct sdio_func	*func;
 	struct mutex		func_lock;
 	struct mutex		func_lock;
 	struct task_struct	*in_sdio_uart_irq;
 	struct task_struct	*in_sdio_uart_irq;
@@ -87,6 +87,7 @@ struct sdio_uart_port {
 	struct uart_icount	icount;
 	struct uart_icount	icount;
 	unsigned int		uartclk;
 	unsigned int		uartclk;
 	unsigned int		mctrl;
 	unsigned int		mctrl;
+	unsigned int		rx_mctrl;
 	unsigned int		read_status_mask;
 	unsigned int		read_status_mask;
 	unsigned int		ignore_status_mask;
 	unsigned int		ignore_status_mask;
 	unsigned char		x_char;
 	unsigned char		x_char;
@@ -102,7 +103,6 @@ static int sdio_uart_add_port(struct sdio_uart_port *port)
 	int index, ret = -EBUSY;
 	int index, ret = -EBUSY;
 
 
 	kref_init(&port->kref);
 	kref_init(&port->kref);
-	mutex_init(&port->open_lock);
 	mutex_init(&port->func_lock);
 	mutex_init(&port->func_lock);
 	spin_lock_init(&port->write_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)
 static void sdio_uart_port_remove(struct sdio_uart_port *port)
 {
 {
 	struct sdio_func *func;
 	struct sdio_func *func;
+	struct tty_struct *tty;
 
 
 	BUG_ON(sdio_uart_table[port->index] != port);
 	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.
 	 * give up on that port ASAP.
 	 * Beware: the lock ordering is critical.
 	 * Beware: the lock ordering is critical.
 	 */
 	 */
-	mutex_lock(&port->open_lock);
+	mutex_lock(&port->port.mutex);
 	mutex_lock(&port->func_lock);
 	mutex_lock(&port->func_lock);
 	func = port->func;
 	func = port->func;
 	sdio_claim_host(func);
 	sdio_claim_host(func);
 	port->func = NULL;
 	port->func = NULL;
 	mutex_unlock(&port->func_lock);
 	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_release_irq(func);
 	sdio_disable_func(func);
 	sdio_disable_func(func);
 	sdio_release_host(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 char status;
 	unsigned int ret;
 	unsigned int ret;
 
 
+	/* FIXME: What stops this losing the delta bits and breaking
+	   sdio_uart_check_modem_status ? */
 	status = sdio_in(port, UART_MSR);
 	status = sdio_in(port, UART_MSR);
 
 
 	ret = 0;
 	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,
 static void sdio_uart_receive_chars(struct sdio_uart_port *port,
 				    unsigned int *status)
 				    unsigned int *status)
 {
 {
-	struct tty_struct *tty = port->tty;
+	struct tty_struct *tty = tty_port_tty_get(&port->port);
 	unsigned int ch, flag;
 	unsigned int ch, flag;
 	int max_count = 256;
 	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)
 		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,
 		 * Overrun is special.  Since it's reported immediately,
 		 * it doesn't affect the current character.
 		 * it doesn't affect the current character.
 		 */
 		 */
 		if (*status & ~port->ignore_status_mask & UART_LSR_OE)
 		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);
 		*status = sdio_in(port, UART_LSR);
 	} while ((*status & UART_LSR_DR) && (max_count-- > 0));
 	} 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)
 static void sdio_uart_transmit_chars(struct sdio_uart_port *port)
 {
 {
 	struct circ_buf *xmit = &port->xmit;
 	struct circ_buf *xmit = &port->xmit;
 	int count;
 	int count;
+	struct tty_struct *tty;
 
 
 	if (port->x_char) {
 	if (port->x_char) {
 		sdio_out(port, UART_TX, 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;
 		port->x_char = 0;
 		return;
 		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);
 		sdio_uart_stop_tx(port);
+		tty_kref_put(tty);
 		return;
 		return;
 	}
 	}
 
 
@@ -468,15 +486,17 @@ static void sdio_uart_transmit_chars(struct sdio_uart_port *port)
 	} while (--count > 0);
 	} while (--count > 0);
 
 
 	if (circ_chars_pending(xmit) < WAKEUP_CHARS)
 	if (circ_chars_pending(xmit) < WAKEUP_CHARS)
-		tty_wakeup(port->tty);
+		tty_wakeup(tty);
 
 
 	if (circ_empty(xmit))
 	if (circ_empty(xmit))
 		sdio_uart_stop_tx(port);
 		sdio_uart_stop_tx(port);
+	tty_kref_put(tty);
 }
 }
 
 
 static void sdio_uart_check_modem_status(struct sdio_uart_port *port)
 static void sdio_uart_check_modem_status(struct sdio_uart_port *port)
 {
 {
 	int status;
 	int status;
+	struct tty_struct *tty;
 
 
 	status = sdio_in(port, UART_MSR);
 	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++;
 		port->icount.rng++;
 	if (status & UART_MSR_DDSR)
 	if (status & UART_MSR_DDSR)
 		port->icount.dsr++;
 		port->icount.dsr++;
-	if (status & UART_MSR_DDCD)
+	if (status & UART_MSR_DDCD) {
 		port->icount.dcd++;
 		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) {
 	if (status & UART_MSR_DCTS) {
 		port->icount.cts++;
 		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);
 			int cts = (status & UART_MSR_CTS);
-			if (port->tty->hw_stopped) {
+			if (tty->hw_stopped) {
 				if (cts) {
 				if (cts) {
-					port->tty->hw_stopped = 0;
+					tty->hw_stopped = 0;
 					sdio_uart_start_tx(port);
 					sdio_uart_start_tx(port);
-					tty_wakeup(port->tty);
+					tty_wakeup(tty);
 				}
 				}
 			} else {
 			} else {
 				if (!cts) {
 				if (!cts) {
-					port->tty->hw_stopped = 1;
+					tty->hw_stopped = 1;
 					sdio_uart_stop_tx(port);
 					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;
 	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;
 	unsigned long page;
 	int ret;
 	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
 	 * Set the TTY IO error marker - we will only clear this
 	 * once we have successfully opened the port.
 	 * 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. */
 	/* Initialise and allocate the transmit buffer. */
 	page = __get_free_page(GFP_KERNEL);
 	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);
 	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;
 	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);
 		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))
 		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 */
 	/* Kick the IRQ handler once while we're still holding the host lock */
 	sdio_uart_irq(port->func);
 	sdio_uart_irq(port->func);
@@ -621,8 +709,20 @@ err1:
 	return ret;
 	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;
 	int ret;
 
 
 	ret = sdio_uart_claim_func(port);
 	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);
 	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 */
 	/* Disable interrupts from this port */
 	sdio_release_irq(port->func);
 	sdio_release_irq(port->func);
 	port->ier = 0;
 	port->ier = 0;
@@ -661,77 +755,70 @@ skip:
 	free_page((unsigned long)port->xmit.buf);
 	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)
 static void sdio_uart_close(struct tty_struct *tty, struct file * filp)
 {
 {
 	struct sdio_uart_port *port = tty->driver_data;
 	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)
 			   int count)
 {
 {
 	struct sdio_uart_port *port = tty->driver_data;
 	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);
 	spin_unlock(&port->write_lock);
 
 
-	if ( !(port->ier & UART_IER_THRI)) {
+	if (!(port->ier & UART_IER_THRI)) {
 		int err = sdio_uart_claim_func(port);
 		int err = sdio_uart_claim_func(port);
 		if (!err) {
 		if (!err) {
 			sdio_uart_start_tx(port);
 			sdio_uart_start_tx(port);
@@ -843,17 +930,12 @@ static void sdio_uart_unthrottle(struct tty_struct *tty)
 	sdio_uart_release_func(port);
 	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;
 	struct sdio_uart_port *port = tty->driver_data;
 	unsigned int cflag = tty->termios->c_cflag;
 	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)
 	if (sdio_uart_claim_func(port) != 0)
 		return;
 		return;
 
 
@@ -928,7 +1010,7 @@ static int sdio_uart_tiocmset(struct tty_struct *tty, struct file *file,
 	int result;
 	int result;
 
 
 	result = sdio_uart_claim_func(port);
 	result = sdio_uart_claim_func(port);
-	if(!result) {
+	if (!result) {
 		sdio_uart_update_mctrl(port, set, clear);
 		sdio_uart_update_mctrl(port, set, clear);
 		sdio_uart_release_func(port);
 		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);
 		struct sdio_uart_port *port = sdio_uart_port_get(i);
 		if (port) {
 		if (port) {
 			seq_printf(m, "%d: uart:SDIO", i);
 			seq_printf(m, "%d: uart:SDIO", i);
-			if(capable(CAP_SYS_ADMIN)) {
+			if (capable(CAP_SYS_ADMIN)) {
 				seq_printf(m, " tx:%d rx:%d",
 				seq_printf(m, " tx:%d rx:%d",
 					      port->icount.tx, port->icount.rx);
 					      port->icount.tx, port->icount.rx);
 				if (port->icount.frame)
 				if (port->icount.frame)
@@ -994,6 +1076,13 @@ static const struct file_operations sdio_uart_proc_fops = {
 	.release	= single_release,
 	.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 = {
 static const struct tty_operations sdio_uart_ops = {
 	.open			= sdio_uart_open,
 	.open			= sdio_uart_open,
 	.close			= sdio_uart_close,
 	.close			= sdio_uart_close,
@@ -1004,9 +1093,12 @@ static const struct tty_operations sdio_uart_ops = {
 	.throttle		= sdio_uart_throttle,
 	.throttle		= sdio_uart_throttle,
 	.unthrottle		= sdio_uart_unthrottle,
 	.unthrottle		= sdio_uart_unthrottle,
 	.set_termios		= sdio_uart_set_termios,
 	.set_termios		= sdio_uart_set_termios,
+	.hangup			= sdio_uart_hangup,
 	.break_ctl		= sdio_uart_break_ctl,
 	.break_ctl		= sdio_uart_break_ctl,
 	.tiocmget		= sdio_uart_tiocmget,
 	.tiocmget		= sdio_uart_tiocmget,
 	.tiocmset		= sdio_uart_tiocmset,
 	.tiocmset		= sdio_uart_tiocmset,
+	.install		= sdio_uart_install,
+	.cleanup		= sdio_uart_cleanup,
 	.proc_fops		= &sdio_uart_proc_fops,
 	.proc_fops		= &sdio_uart_proc_fops,
 };
 };
 
 
@@ -1043,7 +1135,7 @@ static int sdio_uart_probe(struct sdio_func *func,
 		}
 		}
 		if (!tpl) {
 		if (!tpl) {
 			printk(KERN_WARNING
 			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));
 			       sdio_func_id(func));
 			kfree(port);
 			kfree(port);
 			return -EINVAL;
 			return -EINVAL;
@@ -1068,13 +1160,16 @@ static int sdio_uart_probe(struct sdio_func *func,
 
 
 	port->func = func;
 	port->func = func;
 	sdio_set_drvdata(func, port);
 	sdio_set_drvdata(func, port);
+	tty_port_init(&port->port);
+	port->port.ops = &sdio_uart_port_ops;
 
 
 	ret = sdio_uart_add_port(port);
 	ret = sdio_uart_add_port(port);
 	if (ret) {
 	if (ret) {
 		kfree(port);
 		kfree(port);
 	} else {
 	} else {
 		struct device *dev;
 		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)) {
 		if (IS_ERR(dev)) {
 			sdio_uart_port_remove(port);
 			sdio_uart_port_remove(port);
 			ret = PTR_ERR(dev);
 			ret = PTR_ERR(dev);

+ 13 - 11
drivers/serial/8250.c

@@ -1339,14 +1339,12 @@ static void serial8250_start_tx(struct uart_port *port)
 		serial_out(up, UART_IER, up->ier);
 		serial_out(up, UART_IER, up->ier);
 
 
 		if (up->bugs & UART_BUG_TXEN) {
 		if (up->bugs & UART_BUG_TXEN) {
-			unsigned char lsr, iir;
+			unsigned char lsr;
 			lsr = serial_in(up, UART_LSR);
 			lsr = serial_in(up, UART_LSR);
 			up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
 			up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
-			iir = serial_in(up, UART_IIR) & 0x0f;
 			if ((up->port.type == PORT_RM9000) ?
 			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);
 				transmit_chars(up);
 		}
 		}
 	}
 	}
@@ -2646,7 +2644,7 @@ static void __init serial8250_isa_init_ports(void)
 {
 {
 	struct uart_8250_port *up;
 	struct uart_8250_port *up;
 	static int first = 1;
 	static int first = 1;
-	int i;
+	int i, irqflag = 0;
 
 
 	if (!first)
 	if (!first)
 		return;
 		return;
@@ -2670,6 +2668,9 @@ static void __init serial8250_isa_init_ports(void)
 		up->port.ops = &serial8250_pops;
 		up->port.ops = &serial8250_pops;
 	}
 	}
 
 
+	if (share_irqs)
+		irqflag = IRQF_SHARED;
+
 	for (i = 0, up = serial8250_ports;
 	for (i = 0, up = serial8250_ports;
 	     i < ARRAY_SIZE(old_serial_port) && i < nr_uarts;
 	     i < ARRAY_SIZE(old_serial_port) && i < nr_uarts;
 	     i++, up++) {
 	     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.iotype   = old_serial_port[i].io_type;
 		up->port.regshift = old_serial_port[i].iomem_reg_shift;
 		up->port.regshift = old_serial_port[i].iomem_reg_shift;
 		set_io_from_upio(&up->port);
 		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 plat_serial8250_port *p = dev->dev.platform_data;
 	struct uart_port port;
 	struct uart_port port;
-	int ret, i;
+	int ret, i, irqflag = 0;
 
 
 	memset(&port, 0, sizeof(struct uart_port));
 	memset(&port, 0, sizeof(struct uart_port));
 
 
+	if (share_irqs)
+		irqflag = IRQF_SHARED;
+
 	for (i = 0; p && p->flags != 0; p++, i++) {
 	for (i = 0; p && p->flags != 0; p++, i++) {
 		port.iobase		= p->iobase;
 		port.iobase		= p->iobase;
 		port.membase		= p->membase;
 		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_in		= p->serial_in;
 		port.serial_out		= p->serial_out;
 		port.serial_out		= p->serial_out;
 		port.dev		= &dev->dev;
 		port.dev		= &dev->dev;
-		if (share_irqs)
-			port.irqflags |= IRQF_SHARED;
+		port.irqflags		|= irqflag;
 		ret = serial8250_register_port(&port);
 		ret = serial8250_register_port(&port);
 		if (ret < 0) {
 		if (ret < 0) {
 			dev_err(&dev->dev, "unable to register port at index %d "
 			dev_err(&dev->dev, "unable to register port at index %d "

+ 0 - 8
drivers/serial/jsm/jsm.h

@@ -138,7 +138,6 @@ struct jsm_board
 	u32		nasync;		/* Number of ports on card */
 	u32		nasync;		/* Number of ports on card */
 
 
 	u32		irq;		/* Interrupt request number */
 	u32		irq;		/* Interrupt request number */
-	u64		intr_count;	/* Count of interrupts */
 
 
 	u64		membase;	/* Start of base memory of the card */
 	u64		membase;	/* Start of base memory of the card */
 	u64		membase_end;	/* End 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_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_iflag;	/* channel iflags		*/
 	tcflag_t	ch_c_cflag;	/* channel cflags		*/
 	tcflag_t	ch_c_cflag;	/* channel cflags		*/
 	tcflag_t	ch_c_oflag;	/* channel oflags		*/
 	tcflag_t	ch_c_oflag;	/* channel oflags		*/
@@ -215,11 +212,6 @@ struct jsm_channel {
 	u8		ch_stopc;	/* Stop character		*/
 	u8		ch_stopc;	/* Stop character		*/
 	u8		ch_startc;	/* Start 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_mostat;	/* FEP output modem status	*/
 	u8		ch_mistat;	/* FEP input modem status	*/
 	u8		ch_mistat;	/* FEP input modem status	*/
 
 

+ 47 - 1
drivers/serial/jsm/jsm_driver.c

@@ -48,6 +48,17 @@ struct uart_driver jsm_uart_driver = {
 	.nr		= NR_PORTS,
 	.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;
 int jsm_debug;
 module_param(jsm_debug, int, 0);
 module_param(jsm_debug, int, 0);
 MODULE_PARM_DESC(jsm_debug, "Driver debugging level");
 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,
 	rc = request_irq(brd->irq, brd->bd_ops->intr,
-			IRQF_DISABLED|IRQF_SHARED, "JSM", brd);
+			IRQF_SHARED, "JSM", brd);
 	if (rc) {
 	if (rc) {
 		printk(KERN_WARNING "Failed to hook IRQ %d\n",brd->irq);
 		printk(KERN_WARNING "Failed to hook IRQ %d\n",brd->irq);
 		goto out_iounmap;
 		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_set_drvdata(pdev, brd);
+	pci_save_state(pdev);
 
 
 	return 0;
 	return 0;
  out_free_irq:
  out_free_irq:
@@ -222,8 +234,42 @@ static struct pci_driver jsm_driver = {
 	.id_table	= jsm_pci_tbl,
 	.id_table	= jsm_pci_tbl,
 	.probe		= jsm_probe_one,
 	.probe		= jsm_probe_one,
 	.remove		= __devexit_p(jsm_remove_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)
 static int __init jsm_init_module(void)
 {
 {
 	int rc;
 	int rc;

+ 0 - 8
drivers/serial/jsm/jsm_neo.c

@@ -954,13 +954,8 @@ static void neo_param(struct jsm_channel *ch)
 		ch->ch_flags |= (CH_BAUD0);
 		ch->ch_flags |= (CH_BAUD0);
 		ch->ch_mostat &= ~(UART_MCR_RTS | UART_MCR_DTR);
 		ch->ch_mostat &= ~(UART_MCR_RTS | UART_MCR_DTR);
 		neo_assert_modem_signals(ch);
 		neo_assert_modem_signals(ch);
-		ch->ch_old_baud = 0;
 		return;
 		return;
 
 
-	} else if (ch->ch_custom_speed) {
-			baud = ch->ch_custom_speed;
-			if (ch->ch_flags & CH_BAUD0)
-				ch->ch_flags &= ~(CH_BAUD0);
 	} else {
 	} else {
 		int i;
 		int i;
 		unsigned int cflag;
 		unsigned int cflag;
@@ -1045,7 +1040,6 @@ static void neo_param(struct jsm_channel *ch)
 	quot = ch->ch_bd->bd_dividend / baud;
 	quot = ch->ch_bd->bd_dividend / baud;
 
 
 	if (quot != 0) {
 	if (quot != 0) {
-		ch->ch_old_baud = baud;
 		writeb(UART_LCR_DLAB, &ch->ch_neo_uart->lcr);
 		writeb(UART_LCR_DLAB, &ch->ch_neo_uart->lcr);
 		writeb((quot & 0xff), &ch->ch_neo_uart->txrx);
 		writeb((quot & 0xff), &ch->ch_neo_uart->txrx);
 		writeb((quot >> 8), &ch->ch_neo_uart->ier);
 		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;
 	unsigned long lock_flags2;
 	int outofloop_count = 0;
 	int outofloop_count = 0;
 
 
-	brd->intr_count++;
-
 	/* Lock out the slow poller from running on this board. */
 	/* Lock out the slow poller from running on this board. */
 	spin_lock_irqsave(&brd->bd_intr_lock, lock_flags);
 	spin_lock_irqsave(&brd->bd_intr_lock, lock_flags);
 
 

+ 2 - 4
drivers/serial/jsm/jsm_tty.c

@@ -296,8 +296,6 @@ static void jsm_tty_close(struct uart_port *port)
 		bd->bd_ops->assert_modem_signals(channel);
 		bd->bd_ops->assert_modem_signals(channel);
 	}
 	}
 
 
-	channel->ch_old_baud = 0;
-
 	/* Turn off UART interrupts for this port */
 	/* Turn off UART interrupts for this port */
 	channel->ch_bd->bd_ops->uart_off(channel);
 	channel->ch_bd->bd_ops->uart_off(channel);
 
 
@@ -432,7 +430,7 @@ int __devinit jsm_tty_init(struct jsm_board *brd)
 	return 0;
 	return 0;
 }
 }
 
 
-int __devinit jsm_uart_port_init(struct jsm_board *brd)
+int jsm_uart_port_init(struct jsm_board *brd)
 {
 {
 	int i;
 	int i;
 	unsigned int line;
 	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))
 		if (uart_add_one_port (&jsm_uart_driver, &brd->channels[i]->uart_port))
 			printk(KERN_INFO "jsm: add device failed\n");
 			printk(KERN_INFO "jsm: add device failed\n");
 		else
 		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");
 	jsm_printk(INIT, INFO, &brd->pci_dev, "finish\n");

+ 11 - 2
drivers/serial/pxa.c

@@ -438,6 +438,7 @@ serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios,
 	unsigned char cval, fcr = 0;
 	unsigned char cval, fcr = 0;
 	unsigned long flags;
 	unsigned long flags;
 	unsigned int baud, quot;
 	unsigned int baud, quot;
+	unsigned int dll;
 
 
 	switch (termios->c_cflag & CSIZE) {
 	switch (termios->c_cflag & CSIZE) {
 	case CS5:
 	case CS5:
@@ -534,10 +535,18 @@ serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios,
 	else
 	else
 		up->mcr &= ~UART_MCR_AFE;
 		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 */
 	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_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 */
 	up->lcr = cval;					/* Save LCR */
 	serial_pxa_set_mctrl(&up->port, up->port.mctrl);
 	serial_pxa_set_mctrl(&up->port, up->port.mctrl);
 	serial_out(up, UART_FCR, fcr);
 	serial_out(up, UART_FCR, fcr);

+ 16 - 17
drivers/serial/serial_core.c

@@ -342,11 +342,11 @@ uart_get_baud_rate(struct uart_port *port, struct ktermios *termios,
 
 
 	if (flags == UPF_SPD_HI)
 	if (flags == UPF_SPD_HI)
 		altbaud = 57600;
 		altbaud = 57600;
-	if (flags == UPF_SPD_VHI)
+	else if (flags == UPF_SPD_VHI)
 		altbaud = 115200;
 		altbaud = 115200;
-	if (flags == UPF_SPD_SHI)
+	else if (flags == UPF_SPD_SHI)
 		altbaud = 230400;
 		altbaud = 230400;
-	if (flags == UPF_SPD_WARP)
+	else if (flags == UPF_SPD_WARP)
 		altbaud = 460800;
 		altbaud = 460800;
 
 
 	for (try = 0; try < 2; try++) {
 	for (try = 0; try < 2; try++) {
@@ -1217,9 +1217,8 @@ static void uart_set_termios(struct tty_struct *tty,
 	/* Handle transition to B0 status */
 	/* Handle transition to B0 status */
 	if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD))
 	if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD))
 		uart_clear_mctrl(state->uart_port, TIOCM_RTS | TIOCM_DTR);
 		uart_clear_mctrl(state->uart_port, TIOCM_RTS | TIOCM_DTR);
-
 	/* Handle transition away from B0 status */
 	/* 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;
 		unsigned int mask = TIOCM_DTR;
 		if (!(cflag & CRTSCTS) ||
 		if (!(cflag & CRTSCTS) ||
 		    !test_bit(TTY_THROTTLED, &tty->flags))
 		    !test_bit(TTY_THROTTLED, &tty->flags))
@@ -1234,9 +1233,8 @@ static void uart_set_termios(struct tty_struct *tty,
 		__uart_start(tty);
 		__uart_start(tty);
 		spin_unlock_irqrestore(&state->uart_port->lock, flags);
 		spin_unlock_irqrestore(&state->uart_port->lock, flags);
 	}
 	}
-
 	/* Handle turning on CRTSCTS */
 	/* 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);
 		spin_lock_irqsave(&state->uart_port->lock, flags);
 		if (!(state->uart_port->ops->get_mctrl(state->uart_port) & TIOCM_CTS)) {
 		if (!(state->uart_port->ops->get_mctrl(state->uart_port) & TIOCM_CTS)) {
 			tty->hw_stopped = 1;
 			tty->hw_stopped = 1;
@@ -2344,7 +2342,7 @@ static const struct tty_operations uart_ops = {
  */
  */
 int uart_register_driver(struct uart_driver *drv)
 int uart_register_driver(struct uart_driver *drv)
 {
 {
-	struct tty_driver *normal = NULL;
+	struct tty_driver *normal;
 	int i, retval;
 	int i, retval;
 
 
 	BUG_ON(drv->state);
 	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.
 	 * we have a large number of ports to handle.
 	 */
 	 */
 	drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL);
 	drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL);
-	retval = -ENOMEM;
 	if (!drv->state)
 	if (!drv->state)
 		goto out;
 		goto out;
 
 
-	normal  = alloc_tty_driver(drv->nr);
+	normal = alloc_tty_driver(drv->nr);
 	if (!normal)
 	if (!normal)
-		goto out;
+		goto out_kfree;
 
 
 	drv->tty_driver = normal;
 	drv->tty_driver = normal;
 
 
@@ -2393,12 +2390,14 @@ int uart_register_driver(struct uart_driver *drv)
 	}
 	}
 
 
 	retval = tty_register_driver(normal);
 	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;
 }
 }
 
 
 /**
 /**

+ 4 - 3
drivers/usb/serial/opticon.c

@@ -501,12 +501,13 @@ static int opticon_resume(struct usb_interface *intf)
 	struct usb_serial_port *port = serial->port[0];
 	struct usb_serial_port *port = serial->port[0];
 	int result;
 	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);
 		result = usb_submit_urb(priv->bulk_read_urb, GFP_NOIO);
 	else
 	else
 		result = 0;
 		result = 0;
-	mutex_unlock(&port->mutex);
+	mutex_unlock(&port->port.mutex);
 	return result;
 	return result;
 }
 }
 
 

+ 28 - 55
drivers/usb/serial/usb-serial.c

@@ -247,96 +247,66 @@ static int serial_install(struct tty_driver *driver, struct tty_struct *tty)
 	return retval;
 	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;
 	struct usb_serial *serial = port->serial;
 	int retval;
 	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
  * 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 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;
 	struct usb_serial_driver *drv = port->serial->type;
-
 	/*
 	/*
 	 * The console is magical.  Do not hang up the console hardware
 	 * The console is magical.  Do not hang up the console hardware
 	 * or there will be tears.
 	 * or there will be tears.
 	 */
 	 */
 	if (port->console)
 	if (port->console)
 		return;
 		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)
 	if (drv->close)
 		drv->close(port);
 		drv->close(port);
-	mutex_unlock(&port->mutex);
 }
 }
 
 
 static void serial_hangup(struct tty_struct *tty)
 static void serial_hangup(struct tty_struct *tty)
 {
 {
 	struct usb_serial_port *port = tty->driver_data;
 	struct usb_serial_port *port = tty->driver_data;
-
 	dbg("%s - port %d", __func__, port->number);
 	dbg("%s - port %d", __func__, port->number);
-
-	serial_down(port);
 	tty_port_hangup(&port->port);
 	tty_port_hangup(&port->port);
 }
 }
 
 
 static void serial_close(struct tty_struct *tty, struct file *filp)
 static void serial_close(struct tty_struct *tty, struct file *filp)
 {
 {
 	struct usb_serial_port *port = tty->driver_data;
 	struct usb_serial_port *port = tty->driver_data;
-
 	dbg("%s - port %d", __func__, port->number);
 	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 = {
 static const struct tty_port_operations serial_port_ops = {
 	.carrier_raised = serial_carrier_raised,
 	.carrier_raised = serial_carrier_raised,
 	.dtr_rts = serial_dtr_rts,
 	.dtr_rts = serial_dtr_rts,
+	.activate = serial_activate,
+	.shutdown = serial_down,
 };
 };
 
 
 int usb_serial_probe(struct usb_interface *interface,
 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->port.ops = &serial_port_ops;
 		port->serial = serial;
 		port->serial = serial;
 		spin_lock_init(&port->lock);
 		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);
 		INIT_WORK(&port->work, usb_serial_port_work);
 		serial->port[i] = port;
 		serial->port[i] = port;
 		port->dev.parent = &interface->dev;
 		port->dev.parent = &interface->dev;

+ 14 - 2
fs/devpts/inode.c

@@ -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 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));
 	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)
 	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)
 void devpts_pty_kill(struct tty_struct *tty)

+ 0 - 1
include/linux/Kbuild

@@ -214,7 +214,6 @@ unifdef-y += futex.h
 unifdef-y += fs.h
 unifdef-y += fs.h
 unifdef-y += gameport.h
 unifdef-y += gameport.h
 unifdef-y += generic_serial.h
 unifdef-y += generic_serial.h
-unifdef-y += hayesesp.h
 unifdef-y += hdlcdrv.h
 unifdef-y += hdlcdrv.h
 unifdef-y += hdlc.h
 unifdef-y += hdlc.h
 unifdef-y += hdreg.h
 unifdef-y += hdreg.h

+ 0 - 114
include/linux/hayesesp.h

@@ -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 */
-

+ 1 - 0
include/linux/isicom.h

@@ -67,6 +67,7 @@
 
 
 #define		FIRMWARE_LOADED		0x0001
 #define		FIRMWARE_LOADED		0x0001
 #define		BOARD_ACTIVE		0x0002
 #define		BOARD_ACTIVE		0x0002
+#define		BOARD_INIT		0x0004
 
 
  	/* isi_port status bitmap  */
  	/* isi_port status bitmap  */
 
 

+ 23 - 2
include/linux/tty.h

@@ -190,9 +190,17 @@ struct tty_port_operations {
 	/* Control the DTR line */
 	/* Control the DTR line */
 	void (*dtr_rts)(struct tty_port *port, int raise);
 	void (*dtr_rts)(struct tty_port *port, int raise);
 	/* Called when the last close completes or a hangup finishes
 	/* 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 (*shutdown)(struct tty_port *port);
 	void (*drop)(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 {
 struct tty_port {
@@ -206,12 +214,14 @@ struct tty_port {
 	wait_queue_head_t	delta_msr_wait;	/* Modem status change */
 	wait_queue_head_t	delta_msr_wait;	/* Modem status change */
 	unsigned long		flags;		/* TTY flags ASY_*/
 	unsigned long		flags;		/* TTY flags ASY_*/
 	struct mutex		mutex;		/* Locking */
 	struct mutex		mutex;		/* Locking */
+	struct mutex		buf_mutex;	/* Buffer alloc lock */
 	unsigned char		*xmit_buf;	/* Optional buffer */
 	unsigned char		*xmit_buf;	/* Optional buffer */
 	unsigned int		close_delay;	/* Close port delay */
 	unsigned int		close_delay;	/* Close port delay */
 	unsigned int		closing_wait;	/* Delay for output */
 	unsigned int		closing_wait;	/* Delay for output */
 	int			drain_delay;	/* Set to zero if no pure time
 	int			drain_delay;	/* Set to zero if no pure time
 						   based drain is needed else
 						   based drain is needed else
 						   set to size of fifo */
 						   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);
 		struct tty_driver *driver, int idx);
 extern struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
 extern struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
 								int first_ok);
 								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 int tty_init_termios(struct tty_struct *tty);
 
 
 extern struct tty_struct *tty_pair_get_tty(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 void tty_port_init(struct tty_port *port);
 extern int tty_port_alloc_xmit_buf(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_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 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 void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty);
 extern int tty_port_carrier_raised(struct tty_port *port);
 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_end(struct tty_port *port, struct tty_struct *tty);
 extern void tty_port_close(struct tty_port *port,
 extern void tty_port_close(struct tty_port *port,
 				struct tty_struct *tty, struct file *filp);
 				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)
 extern inline int tty_port_users(struct tty_port *port)
 {
 {
 	return port->count + port->blocked_open;
 	return port->count + port->blocked_open;

+ 0 - 3
include/linux/usb/serial.h

@@ -39,8 +39,6 @@ enum port_dev_state {
  * @serial: pointer back to the struct usb_serial owner of this port.
  * @serial: pointer back to the struct usb_serial owner of this port.
  * @port: pointer to the corresponding tty_port for this port.
  * @port: pointer to the corresponding tty_port for this port.
  * @lock: spinlock to grab when updating portions of this structure.
  * @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).
  * @number: the number of the port (the minor number).
  * @interrupt_in_buffer: pointer to the interrupt in buffer for this port.
  * @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.
  * @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 usb_serial	*serial;
 	struct tty_port		port;
 	struct tty_port		port;
 	spinlock_t		lock;
 	spinlock_t		lock;
-	struct mutex            mutex;
 	unsigned char		number;
 	unsigned char		number;
 
 
 	unsigned char		*interrupt_in_buffer;
 	unsigned char		*interrupt_in_buffer;

+ 1 - 1
kernel/exit.c

@@ -971,7 +971,7 @@ NORET_TYPE void do_exit(long code)
 	exit_thread();
 	exit_thread();
 	cgroup_exit(tsk, 1);
 	cgroup_exit(tsk, 1);
 
 
-	if (group_dead && tsk->signal->leader)
+	if (group_dead)
 		disassociate_ctty(1);
 		disassociate_ctty(1);
 
 
 	module_put(task_thread_info(tsk)->exec_domain->module);
 	module_put(task_thread_info(tsk)->exec_domain->module);