]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
Merge branch 'tty-updates' from Alan
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 2 Jan 2009 18:25:51 +0000 (10:25 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 2 Jan 2009 18:26:01 +0000 (10:26 -0800)
* tty-updates: (75 commits)
  serial_8250: support for Sealevel Systems Model 7803 COMM+8
  hso maintainers update patch
  hso modem detect fix patch against Alan Cox'es tty tree
  tty: Fix an ircomm warning and note another bug
  drivers/char/cyclades.c: cy_pci_probe: fix error path
  Serial: UART driver changes for Cavium OCTEON.
  Serial: Allow port type to be specified when calling serial8250_register_port.
  8250: Serial driver changes to support future Cavium OCTEON serial patches.
  8250: Don't clobber spinlocks.
  fix for tty-serial-move-port
  tty: We want the port object to be persistent
  __FUNCTION__ is gcc-specific, use __func__
  serial: RS485 ioctl structure uses __u32 include linux/types.h
  tty: Drop the lock_kernel in the private ioctl hook
  synclink_cs: Convert to tty_port
  tty: use port methods for the rocket driver
  tty: kref the rocket driver
  tty: make rocketport use standard port->flags
  tty: Redo the rocket driver locking
  tty: Make epca use the port helpers
  ...

64 files changed:
Documentation/filesystems/devpts.txt [new file with mode: 0644]
MAINTAINERS
drivers/char/Kconfig
drivers/char/amiserial.c
drivers/char/cyclades.c
drivers/char/epca.c
drivers/char/esp.c
drivers/char/generic_serial.c
drivers/char/hvc_console.c
drivers/char/hvsi.c
drivers/char/isicom.c
drivers/char/istallion.c
drivers/char/moxa.c
drivers/char/mxser.c
drivers/char/n_r3964.c
drivers/char/n_tty.c
drivers/char/nozomi.c
drivers/char/pcmcia/synclink_cs.c
drivers/char/pty.c
drivers/char/rio/rio_linux.c
drivers/char/riscom8.c
drivers/char/rocket.c
drivers/char/rocket.h
drivers/char/rocket_int.h
drivers/char/selection.c
drivers/char/ser_a2232.c
drivers/char/serial167.c
drivers/char/specialix.c
drivers/char/stallion.c
drivers/char/sx.c
drivers/char/synclink.c
drivers/char/synclink_gt.c
drivers/char/synclinkmp.c
drivers/char/tty_io.c
drivers/char/tty_ldisc.c
drivers/char/tty_port.c
drivers/char/vme_scc.c
drivers/char/vt.c
drivers/char/vt_ioctl.c
drivers/net/usb/hso.c
drivers/serial/8250.c
drivers/serial/8250_pci.c
drivers/serial/bfin_5xx.c
drivers/serial/bfin_sport_uart.c
drivers/serial/jsm/jsm_tty.c
drivers/serial/serial_core.c
drivers/usb/serial/console.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/kl5kusb105.c
drivers/usb/serial/mct_u232.c
drivers/usb/serial/mos7840.c
drivers/usb/serial/sierra.c
drivers/usb/serial/usb-serial.c
fs/devpts/inode.c
include/linux/8250_pci.h
include/linux/generic_serial.h
include/linux/istallion.h
include/linux/pci_ids.h
include/linux/serial.h
include/linux/serial_8250.h
include/linux/serial_core.h
include/linux/tty.h
include/linux/tty_driver.h
net/irda/ircomm/ircomm_tty.c

diff --git a/Documentation/filesystems/devpts.txt b/Documentation/filesystems/devpts.txt
new file mode 100644 (file)
index 0000000..68dffd8
--- /dev/null
@@ -0,0 +1,132 @@
+
+To support containers, we now allow multiple instances of devpts filesystem,
+such that indices of ptys allocated in one instance are independent of indices
+allocated in other instances of devpts.
+
+To preserve backward compatibility, this support for multiple instances is
+enabled only if:
+
+       - CONFIG_DEVPTS_MULTIPLE_INSTANCES=y, and
+       - '-o newinstance' mount option is specified while mounting devpts
+
+IOW, devpts now supports both single-instance and multi-instance semantics.
+
+If CONFIG_DEVPTS_MULTIPLE_INSTANCES=n, there is no change in behavior and
+this referred to as the "legacy" mode. In this mode, the new mount options
+(-o newinstance and -o ptmxmode) will be ignored with a 'bogus option' message
+on console.
+
+If CONFIG_DEVPTS_MULTIPLE_INSTANCES=y and devpts is mounted without the
+'newinstance' option (as in current start-up scripts) the new mount binds
+to the initial kernel mount of devpts. This mode is referred to as the
+'single-instance' mode and the current, single-instance semantics are
+preserved, i.e PTYs are common across the system.
+
+The only difference between this single-instance mode and the legacy mode
+is the presence of new, '/dev/pts/ptmx' node with permissions 0000, which
+can safely be ignored.
+
+If CONFIG_DEVPTS_MULTIPLE_INSTANCES=y and 'newinstance' option is specified,
+the mount is considered to be in the multi-instance mode and a new instance
+of the devpts fs is created. Any ptys created in this instance are independent
+of ptys in other instances of devpts. Like in the single-instance mode, the
+/dev/pts/ptmx node is present. To effectively use the multi-instance mode,
+open of /dev/ptmx must be a redirected to '/dev/pts/ptmx' using a symlink or
+bind-mount.
+
+Eg: A container startup script could do the following:
+
+       $ chmod 0666 /dev/pts/ptmx
+       $ rm /dev/ptmx
+       $ ln -s pts/ptmx /dev/ptmx
+       $ ns_exec -cm /bin/bash
+
+       # We are now in new container
+
+       $ umount /dev/pts
+       $ mount -t devpts -o newinstance lxcpts /dev/pts
+       $ sshd -p 1234
+
+where 'ns_exec -cm /bin/bash' calls clone() with CLONE_NEWNS flag and execs
+/bin/bash in the child process.  A pty created by the sshd is not visible in
+the original mount of /dev/pts.
+
+User-space changes
+------------------
+
+In multi-instance mode (i.e '-o newinstance' mount option is specified at least
+once), following user-space issues should be noted.
+
+1. If -o newinstance mount option is never used, /dev/pts/ptmx can be ignored
+   and no change is needed to system-startup scripts.
+
+2. To effectively use multi-instance mode (i.e -o newinstance is specified)
+   administrators or startup scripts should "redirect" open of /dev/ptmx to
+   /dev/pts/ptmx using either a bind mount or symlink.
+
+       $ mount -t devpts -o newinstance devpts /dev/pts
+
+   followed by either
+
+       $ rm /dev/ptmx
+       $ ln -s pts/ptmx /dev/ptmx
+       $ chmod 666 /dev/pts/ptmx
+   or
+       $ mount -o bind /dev/pts/ptmx /dev/ptmx
+
+3. The '/dev/ptmx -> pts/ptmx' symlink is the preferred method since it
+   enables better error-reporting and treats both single-instance and
+   multi-instance mounts similarly.
+
+   But this method requires that system-startup scripts set the mode of
+   /dev/pts/ptmx correctly (default mode is 0000). The scripts can set the
+   mode by, either
+
+       - adding ptmxmode mount option to devpts entry in /etc/fstab, or
+       - using 'chmod 0666 /dev/pts/ptmx'
+
+4. If multi-instance mode mount is needed for containers, but the system
+   startup scripts have not yet been updated, container-startup scripts
+   should bind mount /dev/ptmx to /dev/pts/ptmx to avoid breaking single-
+   instance mounts.
+
+   Or, in general, container-startup scripts should use:
+
+       mount -t devpts -o newinstance -o ptmxmode=0666 devpts /dev/pts
+       if [ ! -L /dev/ptmx ]; then
+               mount -o bind /dev/pts/ptmx /dev/ptmx
+       fi
+
+   When all devpts mounts are multi-instance, /dev/ptmx can permanently be
+   a symlink to pts/ptmx and the bind mount can be ignored.
+
+5. A multi-instance mount that is not accompanied by the /dev/ptmx to
+   /dev/pts/ptmx redirection would result in an unusable/unreachable pty.
+
+       mount -t devpts -o newinstance lxcpts /dev/pts
+
+   immediately followed by:
+
+       open("/dev/ptmx")
+
+    would create a pty, say /dev/pts/7, in the initial kernel mount.
+    But /dev/pts/7 would be invisible in the new mount.
+
+6. The permissions for /dev/pts/ptmx node should be specified when mounting
+   /dev/pts, using the '-o ptmxmode=%o' mount option (default is 0000).
+
+       mount -t devpts -o newinstance -o ptmxmode=0644 devpts /dev/pts
+
+   The permissions can be later be changed as usual with 'chmod'.
+
+       chmod 666 /dev/pts/ptmx
+
+7. A mount of devpts without the 'newinstance' option results in binding to
+   initial kernel mount.  This behavior while preserving legacy semantics,
+   does not provide strict isolation in a container environment. i.e by
+   mounting devpts without the 'newinstance' option, a container could
+   get visibility into the 'host' or root container's devpts.
+   
+   To workaround this and have strict isolation, all mounts of devpts,
+   including the mount in the root container, should use the newinstance
+   option.
index ceb32ee51f9de33077fcf95a3ff1845465b2a130..d5fc534a1085f2611c7ecd98f23e53f987566247 100644 (file)
@@ -2049,6 +2049,12 @@ M:       mikulas@artax.karlin.mff.cuni.cz
 W:     http://artax.karlin.mff.cuni.cz/~mikulas/vyplody/hpfs/index-e.cgi
 S:     Maintained
 
+HSO    3G Modem Driver (hso.c)
+P:     Denis Joseph Barrow
+M:     d.barow@option.com
+W:     http://www.pharscape.org
+S:     Maintained
+
 HTCPEN TOUCHSCREEN DRIVER
 P:     Pau Oliva Fora
 M:     pof@eslack.org
index c602b547cc6e08afd842182b80fac140c13766cb..1697043119bd27084024b1dd57996f71561ce4a1 100644 (file)
@@ -190,7 +190,7 @@ config DIGIEPCA
 
 config ESPSERIAL
        tristate "Hayes ESP serial port support"
-       depends on SERIAL_NONSTANDARD && ISA && ISA_DMA_API
+       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
@@ -443,6 +443,17 @@ config UNIX98_PTYS
          All modern Linux systems use the Unix98 ptys.  Say Y unless
          you're on an embedded system and want to conserve memory.
 
+config DEVPTS_MULTIPLE_INSTANCES
+       bool "Support multiple instances of devpts"
+       depends on UNIX98_PTYS
+       default n
+       ---help---
+         Enable support for multiple instances of devpts filesystem.
+         If you want to have isolated PTY namespaces (eg: in containers),
+         say Y here.  Otherwise, say N. If enabled, each mount of devpts
+         filesystem with the '-o newinstance' option will create an
+         independent PTY namespace.
+
 config LEGACY_PTYS
        bool "Legacy (BSD) PTY support"
        default y
index b97aebd7aeb8d84af42f72291b06ecb3dcb6dff8..4e0cfdeab1462a8b16641c6ef54cc480ccbe8fc9 100644 (file)
@@ -170,7 +170,7 @@ static __inline__ void rtsdtr_ctrl(int bits)
  */
 static void rs_stop(struct tty_struct *tty)
 {
-       struct async_struct *info = (struct async_struct *)tty->driver_data;
+       struct async_struct *info = tty->driver_data;
        unsigned long flags;
 
        if (serial_paranoia_check(info, tty->name, "rs_stop"))
@@ -190,7 +190,7 @@ static void rs_stop(struct tty_struct *tty)
 
 static void rs_start(struct tty_struct *tty)
 {
-       struct async_struct *info = (struct async_struct *)tty->driver_data;
+       struct async_struct *info = tty->driver_data;
        unsigned long flags;
 
        if (serial_paranoia_check(info, tty->name, "rs_start"))
@@ -861,7 +861,7 @@ static int rs_put_char(struct tty_struct *tty, unsigned char ch)
 
 static void rs_flush_chars(struct tty_struct *tty)
 {
-       struct async_struct *info = (struct async_struct *)tty->driver_data;
+       struct async_struct *info = tty->driver_data;
        unsigned long flags;
 
        if (serial_paranoia_check(info, tty->name, "rs_flush_chars"))
@@ -934,7 +934,7 @@ static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count
 
 static int rs_write_room(struct tty_struct *tty)
 {
-       struct async_struct *info = (struct async_struct *)tty->driver_data;
+       struct async_struct *info = tty->driver_data;
 
        if (serial_paranoia_check(info, tty->name, "rs_write_room"))
                return 0;
@@ -943,7 +943,7 @@ static int rs_write_room(struct tty_struct *tty)
 
 static int rs_chars_in_buffer(struct tty_struct *tty)
 {
-       struct async_struct *info = (struct async_struct *)tty->driver_data;
+       struct async_struct *info = tty->driver_data;
 
        if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer"))
                return 0;
@@ -952,7 +952,7 @@ static int rs_chars_in_buffer(struct tty_struct *tty)
 
 static void rs_flush_buffer(struct tty_struct *tty)
 {
-       struct async_struct *info = (struct async_struct *)tty->driver_data;
+       struct async_struct *info = tty->driver_data;
        unsigned long flags;
 
        if (serial_paranoia_check(info, tty->name, "rs_flush_buffer"))
@@ -969,7 +969,7 @@ static void rs_flush_buffer(struct tty_struct *tty)
  */
 static void rs_send_xchar(struct tty_struct *tty, char ch)
 {
-       struct async_struct *info = (struct async_struct *)tty->driver_data;
+       struct async_struct *info = tty->driver_data;
         unsigned long flags;
 
        if (serial_paranoia_check(info, tty->name, "rs_send_char"))
@@ -1004,7 +1004,7 @@ static void rs_send_xchar(struct tty_struct *tty, char ch)
  */
 static void rs_throttle(struct tty_struct * tty)
 {
-       struct async_struct *info = (struct async_struct *)tty->driver_data;
+       struct async_struct *info = tty->driver_data;
        unsigned long flags;
 #ifdef SERIAL_DEBUG_THROTTLE
        char    buf[64];
@@ -1029,7 +1029,7 @@ static void rs_throttle(struct tty_struct * tty)
 
 static void rs_unthrottle(struct tty_struct * tty)
 {
-       struct async_struct *info = (struct async_struct *)tty->driver_data;
+       struct async_struct *info = tty->driver_data;
        unsigned long flags;
 #ifdef SERIAL_DEBUG_THROTTLE
        char    buf[64];
@@ -1194,7 +1194,7 @@ static int get_lsr_info(struct async_struct * info, unsigned int __user *value)
 
 static int rs_tiocmget(struct tty_struct *tty, struct file *file)
 {
-       struct async_struct * info = (struct async_struct *)tty->driver_data;
+       struct async_struct * info = tty->driver_data;
        unsigned char control, status;
        unsigned long flags;
 
@@ -1217,7 +1217,7 @@ static int rs_tiocmget(struct tty_struct *tty, struct file *file)
 static int rs_tiocmset(struct tty_struct *tty, struct file *file,
                       unsigned int set, unsigned int clear)
 {
-       struct async_struct * info = (struct async_struct *)tty->driver_data;
+       struct async_struct * info = tty->driver_data;
        unsigned long flags;
 
        if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
@@ -1244,7 +1244,7 @@ static int rs_tiocmset(struct tty_struct *tty, struct file *file,
  */
 static int rs_break(struct tty_struct *tty, int break_state)
 {
-       struct async_struct * info = (struct async_struct *)tty->driver_data;
+       struct async_struct * info = tty->driver_data;
        unsigned long flags;
 
        if (serial_paranoia_check(info, tty->name, "rs_break"))
@@ -1264,7 +1264,7 @@ static int rs_break(struct tty_struct *tty, int break_state)
 static int rs_ioctl(struct tty_struct *tty, struct file * file,
                    unsigned int cmd, unsigned long arg)
 {
-       struct async_struct * info = (struct async_struct *)tty->driver_data;
+       struct async_struct * info = tty->driver_data;
        struct async_icount cprev, cnow;        /* kernel counter temps */
        struct serial_icounter_struct icount;
        void __user *argp = (void __user *)arg;
@@ -1368,7 +1368,7 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
 
 static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
 {
-       struct async_struct *info = (struct async_struct *)tty->driver_data;
+       struct async_struct *info = tty->driver_data;
        unsigned long flags;
        unsigned int cflag = tty->termios->c_cflag;
 
@@ -1428,7 +1428,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
  */
 static void rs_close(struct tty_struct *tty, struct file * filp)
 {
-       struct async_struct * info = (struct async_struct *)tty->driver_data;
+       struct async_struct * info = tty->driver_data;
        struct serial_state *state;
        unsigned long flags;
 
@@ -1523,7 +1523,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
  */
 static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
 {
-       struct async_struct * info = (struct async_struct *)tty->driver_data;
+       struct async_struct * info = tty->driver_data;
        unsigned long orig_jiffies, char_time;
        int lsr;
 
@@ -1587,7 +1587,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
  */
 static void rs_hangup(struct tty_struct *tty)
 {
-       struct async_struct * info = (struct async_struct *)tty->driver_data;
+       struct async_struct * info = tty->driver_data;
        struct serial_state *state = info->state;
 
        if (serial_paranoia_check(info, tty->name, "rs_hangup"))
index 5e5b1dc1a0a72be733ce32b93966113e6cf224c7..6a59f72a9c2157697de1a3228a19296e1fc89fb2 100644 (file)
@@ -5010,7 +5010,7 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
                if (nchan == 0) {
                        dev_err(&pdev->dev, "Cyclom-Y PCI host card with no "
                                        "Serial-Modules\n");
-                       return -EIO;
+                       goto err_unmap;
                }
        } else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) {
                struct RUNTIME_9060 __iomem *ctl_addr;
index cf2461d34e5fc17d56ca16e5e165a092bd0b6136..39ad820b2350b651437513080d3afbbc478be0fe 100644 (file)
@@ -69,7 +69,9 @@ static int invalid_lilo_config;
 
 /*
  * The ISA boards do window flipping into the same spaces so its only sane with
- * a single lock. It's still pretty efficient.
+ * a single lock. It's still pretty efficient. This lock guards the hardware
+ * and the tty_port lock guards the kernel side stuff like use counts. Take
+ * this lock inside the port lock if you must take both.
  */
 static DEFINE_SPINLOCK(epca_lock);
 
@@ -156,14 +158,12 @@ static struct channel *verifyChannel(struct tty_struct *);
 static void pc_sched_event(struct channel *, int);
 static void epca_error(int, char *);
 static void pc_close(struct tty_struct *, struct file *);
-static void shutdown(struct channel *);
+static void shutdown(struct channel *, struct tty_struct *tty);
 static void pc_hangup(struct tty_struct *);
 static int pc_write_room(struct tty_struct *);
 static int pc_chars_in_buffer(struct tty_struct *);
 static void pc_flush_buffer(struct tty_struct *);
 static void pc_flush_chars(struct tty_struct *);
-static int block_til_ready(struct tty_struct *, struct file *,
-                       struct channel *);
 static int pc_open(struct tty_struct *, struct file *);
 static void post_fep_init(unsigned int crd);
 static void epcapoll(unsigned long);
@@ -173,7 +173,7 @@ static unsigned termios2digi_h(struct channel *ch, unsigned);
 static unsigned termios2digi_i(struct channel *ch, unsigned);
 static unsigned termios2digi_c(struct channel *ch, unsigned);
 static void epcaparam(struct tty_struct *, struct channel *);
-static void receive_data(struct channel *);
+static void receive_data(struct channel *, struct tty_struct *tty);
 static int pc_ioctl(struct tty_struct *, struct file *,
                        unsigned int, unsigned long);
 static int info_ioctl(struct tty_struct *, struct file *,
@@ -392,7 +392,7 @@ static struct channel *verifyChannel(struct tty_struct *tty)
         * through tty->driver_data this should catch it.
         */
        if (tty) {
-               struct channel *ch = (struct channel *)tty->driver_data;
+               struct channel *ch = tty->driver_data;
                if (ch >= &digi_channels[0] && ch < &digi_channels[nbdevs]) {
                        if (ch->magic == EPCA_MAGIC)
                                return ch;
@@ -419,76 +419,34 @@ static void epca_error(int line, char *msg)
 static void pc_close(struct tty_struct *tty, struct file *filp)
 {
        struct channel *ch;
-       unsigned long flags;
+       struct tty_port *port;
        /*
         * verifyChannel returns the channel from the tty struct if it is
         * valid. This serves as a sanity check.
         */
        ch = verifyChannel(tty);
-       if (ch != NULL) {
-               spin_lock_irqsave(&epca_lock, flags);
-               if (tty_hung_up_p(filp)) {
-                       spin_unlock_irqrestore(&epca_lock, flags);
-                       return;
-               }
-               if (ch->port.count-- > 1)  {
-                       /* Begin channel is open more than once */
-                       /*
-                        * Return without doing anything. Someone might still
-                        * be using the channel.
-                        */
-                       spin_unlock_irqrestore(&epca_lock, flags);
-                       return;
-               }
-               /* Port open only once go ahead with shutdown & reset */
-               BUG_ON(ch->port.count < 0);
-
-               /*
-                * Let the rest of the driver know the channel is being closed.
-                * This becomes important if an open is attempted before close
-                * is finished.
-                */
-               ch->port.flags |= ASYNC_CLOSING;
-               tty->closing = 1;
-
-               spin_unlock_irqrestore(&epca_lock, flags);
-
-               if (ch->port.flags & ASYNC_INITIALIZED)  {
-                       /* Setup an event to indicate when the
-                          transmit buffer empties */
-                       setup_empty_event(tty, ch);
-                       /* 30 seconds timeout */
-                       tty_wait_until_sent(tty, 3000);
-               }
-               pc_flush_buffer(tty);
+       if (ch == NULL)
+               return;
+       port = &ch->port;
 
-               tty_ldisc_flush(tty);
-               shutdown(ch);
+       if (tty_port_close_start(port, tty, filp) == 0)
+               return;
 
-               spin_lock_irqsave(&epca_lock, flags);
-               tty->closing = 0;
-               ch->event = 0;
-               ch->port.tty = NULL;
-               spin_unlock_irqrestore(&epca_lock, flags);
+       pc_flush_buffer(tty);
+       shutdown(ch, tty);
 
-               if (ch->port.blocked_open) {
-                       if (ch->close_delay)
-                               msleep_interruptible(jiffies_to_msecs(ch->close_delay));
-                       wake_up_interruptible(&ch->port.open_wait);
-               }
-               ch->port.flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED |
-                                       ASYNC_CLOSING);
-               wake_up_interruptible(&ch->port.close_wait);
-       }
+       tty_port_close_end(port, tty);
+       ch->event = 0;  /* FIXME: review ch->event locking */
+       tty_port_tty_set(port, NULL);
 }
 
-static void shutdown(struct channel *ch)
+static void shutdown(struct channel *ch, struct tty_struct *tty)
 {
        unsigned long flags;
-       struct tty_struct *tty;
        struct board_chan __iomem *bc;
+       struct tty_port *port = &ch->port;
 
-       if (!(ch->port.flags & ASYNC_INITIALIZED))
+       if (!(port->flags & ASYNC_INITIALIZED))
                return;
 
        spin_lock_irqsave(&epca_lock, flags);
@@ -503,7 +461,6 @@ static void shutdown(struct channel *ch)
         */
        if (bc)
                writeb(0, &bc->idata);
-       tty = ch->port.tty;
 
        /* If we're a modem control device and HUPCL is on, drop RTS & DTR. */
        if (tty->termios->c_cflag & HUPCL)  {
@@ -517,32 +474,26 @@ static void shutdown(struct channel *ch)
         * will have to reinitialized. Set a flag to indicate this.
         */
        /* Prevent future Digi programmed interrupts from coming active */
-       ch->port.flags &= ~ASYNC_INITIALIZED;
+       port->flags &= ~ASYNC_INITIALIZED;
        spin_unlock_irqrestore(&epca_lock, flags);
 }
 
 static void pc_hangup(struct tty_struct *tty)
 {
        struct channel *ch;
+
        /*
         * verifyChannel returns the channel from the tty struct if it is
         * valid. This serves as a sanity check.
         */
        ch = verifyChannel(tty);
        if (ch != NULL) {
-               unsigned long flags;
-
                pc_flush_buffer(tty);
                tty_ldisc_flush(tty);
-               shutdown(ch);
+               shutdown(ch, tty);
 
-               spin_lock_irqsave(&epca_lock, flags);
-               ch->port.tty   = NULL;
-               ch->event = 0;
-               ch->port.count = 0;
-               ch->port.flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED);
-               spin_unlock_irqrestore(&epca_lock, flags);
-               wake_up_interruptible(&ch->port.open_wait);
+               ch->event = 0;  /* FIXME: review locking of ch->event */
+               tty_port_hangup(&ch->port);
        }
 }
 
@@ -786,100 +737,22 @@ static void pc_flush_chars(struct tty_struct *tty)
        }
 }
 
-static int block_til_ready(struct tty_struct *tty,
-                               struct file *filp, struct channel *ch)
+static int epca_carrier_raised(struct tty_port *port)
 {
-       DECLARE_WAITQUEUE(wait, current);
-       int retval, do_clocal = 0;
-       unsigned long flags;
-
-       if (tty_hung_up_p(filp)) {
-               if (ch->port.flags & ASYNC_HUP_NOTIFY)
-                       retval = -EAGAIN;
-               else
-                       retval = -ERESTARTSYS;
-               return retval;
-       }
-
-       /*
-        * If the device is in the middle of being closed, then block until
-        * it's done, and then try again.
-        */
-       if (ch->port.flags & ASYNC_CLOSING) {
-               interruptible_sleep_on(&ch->port.close_wait);
-
-               if (ch->port.flags & ASYNC_HUP_NOTIFY)
-                       return -EAGAIN;
-               else
-                       return -ERESTARTSYS;
-       }
-
-       if (filp->f_flags & O_NONBLOCK)  {
-               /*
-                * If non-blocking mode is set, then make the check up front
-                * and then exit.
-                */
-               ch->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 */
-
-       retval = 0;
-       add_wait_queue(&ch->port.open_wait, &wait);
-
-       spin_lock_irqsave(&epca_lock, flags);
-       /* We dec count so that pc_close will know when to free things */
-       if (!tty_hung_up_p(filp))
-               ch->port.count--;
-       ch->port.blocked_open++;
-       while (1) {
-               set_current_state(TASK_INTERRUPTIBLE);
-               if (tty_hung_up_p(filp) ||
-                               !(ch->port.flags & ASYNC_INITIALIZED)) {
-                       if (ch->port.flags & ASYNC_HUP_NOTIFY)
-                               retval = -EAGAIN;
-                       else
-                               retval = -ERESTARTSYS;
-                       break;
-               }
-               if (!(ch->port.flags & ASYNC_CLOSING) &&
-                         (do_clocal || (ch->imodem & ch->dcd)))
-                       break;
-               if (signal_pending(current)) {
-                       retval = -ERESTARTSYS;
-                       break;
-               }
-               spin_unlock_irqrestore(&epca_lock, flags);
-               /*
-                * Allow someone else to be scheduled. We will occasionally go
-                * through this loop until one of the above conditions change.
-                * The below schedule call will allow other processes to enter
-                * and prevent this loop from hogging the cpu.
-                */
-               schedule();
-               spin_lock_irqsave(&epca_lock, flags);
-       }
-
-       __set_current_state(TASK_RUNNING);
-       remove_wait_queue(&ch->port.open_wait, &wait);
-       if (!tty_hung_up_p(filp))
-               ch->port.count++;
-       ch->port.blocked_open--;
-
-       spin_unlock_irqrestore(&epca_lock, flags);
-
-       if (retval)
-               return retval;
-
-       ch->port.flags |= ASYNC_NORMAL_ACTIVE;
+       struct channel *ch = container_of(port, struct channel, port);
+       if (ch->imodem & ch->dcd)
+               return 1;
        return 0;
 }
 
+static void epca_raise_dtr_rts(struct tty_port *port)
+{
+}
+
 static int pc_open(struct tty_struct *tty, struct file *filp)
 {
        struct channel *ch;
+       struct tty_port *port;
        unsigned long flags;
        int line, retval, boardnum;
        struct board_chan __iomem *bc;
@@ -890,6 +763,7 @@ static int pc_open(struct tty_struct *tty, struct file *filp)
                return -ENODEV;
 
        ch = &digi_channels[line];
+       port = &ch->port;
        boardnum = ch->boardnum;
 
        /* Check status of board configured in system.  */
@@ -926,22 +800,24 @@ static int pc_open(struct tty_struct *tty, struct file *filp)
                return -ENODEV;
        }
 
-       spin_lock_irqsave(&epca_lock, flags);
+       spin_lock_irqsave(&port->lock, flags);
        /*
         * Every time a channel is opened, increment a counter. This is
         * necessary because we do not wish to flush and shutdown the channel
         * until the last app holding the channel open, closes it.
         */
-       ch->port.count++;
+       port->count++;
        /*
         * Set a kernel structures pointer to our local channel structure. This
         * way we can get to it when passed only a tty struct.
         */
        tty->driver_data = ch;
+       port->tty = tty;
        /*
         * If this is the first time the channel has been opened, initialize
         * the tty->termios struct otherwise let pc_close handle it.
         */
+       spin_lock(&epca_lock);
        globalwinon(ch);
        ch->statusflags = 0;
 
@@ -956,31 +832,33 @@ static int pc_open(struct tty_struct *tty, struct file *filp)
        writew(head, &bc->rout);
 
        /* Set the channels associated tty structure */
-       ch->port.tty = tty;
 
        /*
         * The below routine generally sets up parity, baud, flow control
         * issues, etc.... It effect both control flags and input flags.
         */
        epcaparam(tty, ch);
-       ch->port.flags |= ASYNC_INITIALIZED;
        memoff(ch);
-       spin_unlock_irqrestore(&epca_lock, flags);
+       spin_unlock(&epca_lock);
+       port->flags |= ASYNC_INITIALIZED;
+       spin_unlock_irqrestore(&port->lock, flags);
 
-       retval = block_til_ready(tty, filp, ch);
+       retval = tty_port_block_til_ready(port, tty, filp);
        if (retval)
                return retval;
        /*
         * Set this again in case a hangup set it to zero while this open() was
         * waiting for the line...
         */
-       spin_lock_irqsave(&epca_lock, flags);
-       ch->port.tty = tty;
+       spin_lock_irqsave(&port->lock, flags);
+       port->tty = tty;
+       spin_lock(&epca_lock);
        globalwinon(ch);
        /* Enable Digi Data events */
        writeb(1, &bc->idata);
        memoff(ch);
-       spin_unlock_irqrestore(&epca_lock, flags);
+       spin_unlock(&epca_lock);
+       spin_unlock_irqrestore(&port->lock, flags);
        return 0;
 }
 
@@ -1016,8 +894,11 @@ static void __exit epca_module_exit(void)
                }
                ch = card_ptr[crd];
                for (count = 0; count < bd->numports; count++, ch++) {
-                       if (ch && ch->port.tty)
-                               tty_hangup(ch->port.tty);
+                       struct tty_struct *tty = tty_port_tty_get(&ch->port);
+                       if (tty) {
+                               tty_hangup(tty);
+                               tty_kref_put(tty);
+                       }
                }
        }
        pci_unregister_driver(&epca_driver);
@@ -1042,6 +923,11 @@ static const struct tty_operations pc_ops = {
        .break_ctl = pc_send_break
 };
 
+static const struct tty_port_operations epca_port_ops = {
+       .carrier_raised = epca_carrier_raised,
+       .raise_dtr_rts = epca_raise_dtr_rts,
+};
+
 static int info_open(struct tty_struct *tty, struct file *filp)
 {
        return 0;
@@ -1377,6 +1263,7 @@ static void post_fep_init(unsigned int crd)
                u16 tseg, rseg;
 
                tty_port_init(&ch->port);
+               ch->port.ops = &epca_port_ops;
                ch->brdchan = bc;
                ch->mailbox = gd;
                INIT_WORK(&ch->tqueue, do_softint);
@@ -1428,7 +1315,7 @@ static void post_fep_init(unsigned int crd)
                ch->boardnum   = crd;
                ch->channelnum = i;
                ch->magic      = EPCA_MAGIC;
-               ch->port.tty        = NULL;
+               tty_port_tty_set(&ch->port, NULL);
 
                if (shrinkmem) {
                        fepcmd(ch, SETBUFFER, 32, 0, 0, 0);
@@ -1510,7 +1397,7 @@ static void post_fep_init(unsigned int crd)
                ch->fepstartca = 0;
                ch->fepstopca = 0;
 
-               ch->close_delay = 50;
+               ch->port.close_delay = 50;
 
                spin_unlock_irqrestore(&epca_lock, flags);
        }
@@ -1622,15 +1509,16 @@ static void doevent(int crd)
                if (bc == NULL)
                        goto next;
 
+               tty = tty_port_tty_get(&ch->port);
                if (event & DATA_IND)  { /* Begin DATA_IND */
-                       receive_data(ch);
+                       receive_data(ch, tty);
                        assertgwinon(ch);
                } /* End DATA_IND */
                /* else *//* Fix for DCD transition missed bug */
                if (event & MODEMCHG_IND) {
                        /* A modem signal change has been indicated */
                        ch->imodem = mstat;
-                       if (ch->port.flags & ASYNC_CHECK_CD) {
+                       if (test_bit(ASYNC_CHECK_CD, &ch->port.flags)) {
                                /* We are now receiving dcd */
                                if (mstat & ch->dcd)
                                        wake_up_interruptible(&ch->port.open_wait);
@@ -1638,7 +1526,6 @@ static void doevent(int crd)
                                        pc_sched_event(ch, EPCA_EVENT_HANGUP);
                        }
                }
-               tty = ch->port.tty;
                if (tty) {
                        if (event & BREAK_IND) {
                                /* A break has been indicated */
@@ -1658,6 +1545,7 @@ static void doevent(int crd)
                                        tty_wakeup(tty);
                                }
                        }
+                       tty_kref_put(tty);
                }
 next:
                globalwinon(ch);
@@ -1877,9 +1765,9 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch)
                 * that the driver will wait on carrier detect.
                 */
                if (ts->c_cflag & CLOCAL)
-                       ch->port.flags &= ~ASYNC_CHECK_CD;
+                       clear_bit(ASYNC_CHECK_CD, &ch->port.flags);
                else
-                       ch->port.flags |= ASYNC_CHECK_CD;
+                       set_bit(ASYNC_CHECK_CD, &ch->port.flags);
                mval = ch->m_dtr | ch->m_rts;
        } /* End CBAUD not detected */
        iflag = termios2digi_i(ch, ts->c_iflag);
@@ -1952,11 +1840,10 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch)
 }
 
 /* Caller holds lock */
-static void receive_data(struct channel *ch)
+static void receive_data(struct channel *ch, struct tty_struct *tty)
 {
        unchar *rptr;
        struct ktermios *ts = NULL;
-       struct tty_struct *tty;
        struct board_chan __iomem *bc;
        int dataToRead, wrapgap, bytesAvailable;
        unsigned int tail, head;
@@ -1969,7 +1856,6 @@ static void receive_data(struct channel *ch)
        globalwinon(ch);
        if (ch->statusflags & RXSTOPPED)
                return;
-       tty = ch->port.tty;
        if (tty)
                ts = tty->termios;
        bc = ch->brdchan;
@@ -2029,7 +1915,7 @@ static void receive_data(struct channel *ch)
        globalwinon(ch);
        writew(tail, &bc->rout);
        /* Must be called with global data */
-       tty_schedule_flip(ch->port.tty);
+       tty_schedule_flip(tty);
 }
 
 static int info_ioctl(struct tty_struct *tty, struct file *file,
@@ -2097,7 +1983,7 @@ static int info_ioctl(struct tty_struct *tty, struct file *file,
 
 static int pc_tiocmget(struct tty_struct *tty, struct file *file)
 {
-       struct channel *ch = (struct channel *) tty->driver_data;
+       struct channel *ch = tty->driver_data;
        struct board_chan __iomem *bc;
        unsigned int mstat, mflag = 0;
        unsigned long flags;
@@ -2131,7 +2017,7 @@ static int pc_tiocmget(struct tty_struct *tty, struct file *file)
 static int pc_tiocmset(struct tty_struct *tty, struct file *file,
                       unsigned int set, unsigned int clear)
 {
-       struct channel *ch = (struct channel *) tty->driver_data;
+       struct channel *ch = tty->driver_data;
        unsigned long flags;
 
        if (!ch)
@@ -2178,7 +2064,7 @@ static int pc_ioctl(struct tty_struct *tty, struct file *file,
        unsigned int mflag, mstat;
        unsigned char startc, stopc;
        struct board_chan __iomem *bc;
-       struct channel *ch = (struct channel *) tty->driver_data;
+       struct channel *ch = tty->driver_data;
        void __user *argp = (void __user *)arg;
 
        if (ch)
@@ -2352,15 +2238,16 @@ static void do_softint(struct work_struct *work)
        struct channel *ch = container_of(work, struct channel, tqueue);
        /* Called in response to a modem change event */
        if (ch && ch->magic == EPCA_MAGIC) {
-               struct tty_struct *tty = ch->port.tty;
+               struct tty_struct *tty = tty_port_tty_get(&ch->port);;
 
                if (tty && tty->driver_data) {
                        if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event)) {
                                tty_hangup(tty);
                                wake_up_interruptible(&ch->port.open_wait);
-                               ch->port.flags &= ~ASYNC_NORMAL_ACTIVE;
+                               clear_bit(ASYNC_NORMAL_ACTIVE, &ch->port.flags);
                        }
                }
+               tty_kref_put(tty);
        }
 }
 
@@ -2473,7 +2360,7 @@ static void pc_unthrottle(struct tty_struct *tty)
 
 static int pc_send_break(struct tty_struct *tty, int msec)
 {
-       struct channel *ch = (struct channel *) tty->driver_data;
+       struct channel *ch = tty->driver_data;
        unsigned long flags;
 
        if (msec == -1)
index 7f077c0097f663b5e432d01fb2a40f93c743ad30..45ec263ec012c504080409a2cb399aba7808b8e2 100644 (file)
@@ -2054,6 +2054,15 @@ static void esp_hangup(struct tty_struct *tty)
        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
@@ -2066,17 +2075,19 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
        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) ||
-           (info->port.flags & ASYNC_CLOSING)) {
-               if (info->port.flags & ASYNC_CLOSING)
-                       interruptible_sleep_on(&info->port.close_wait);
+           (port->flags & ASYNC_CLOSING)) {
+               if (port->flags & ASYNC_CLOSING)
+                       interruptible_sleep_on(&port->close_wait);
 #ifdef SERIAL_DO_RESTART
-               if (info->port.flags & ASYNC_HUP_NOTIFY)
+               if (port->flags & ASYNC_HUP_NOTIFY)
                        return -EAGAIN;
                else
                        return -ERESTARTSYS;
@@ -2091,7 +2102,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
         */
        if ((filp->f_flags & O_NONBLOCK) ||
            (tty->flags & (1 << TTY_IO_ERROR))) {
-               info->port.flags |= ASYNC_NORMAL_ACTIVE;
+               port->flags |= ASYNC_NORMAL_ACTIVE;
                return 0;
        }
 
@@ -2101,20 +2112,20 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
        /*
         * Block waiting for the carrier detect and the line to become
         * free (i.e., not in use by the callout).  While we are in
-        * this loop, info->port.count is dropped by one, so that
+        * this loop, port->count is dropped by one, so that
         * rs_close() knows when to free things.  We restore it upon
         * exit, either normal or abnormal.
         */
        retval = 0;
-       add_wait_queue(&info->port.open_wait, &wait);
+       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, info->port.count);
+              info->line, port->count);
 #endif
        spin_lock_irqsave(&info->lock, flags);
        if (!tty_hung_up_p(filp))
-               info->port.count--;
-       info->port.blocked_open++;
+               port->count--;
+       port->blocked_open++;
        while (1) {
                if ((tty->termios->c_cflag & CBAUD)) {
                        unsigned int scratch;
@@ -2129,9 +2140,9 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
                }
                set_current_state(TASK_INTERRUPTIBLE);
                if (tty_hung_up_p(filp) ||
-                   !(info->port.flags & ASYNC_INITIALIZED)) {
+                   !(port->flags & ASYNC_INITIALIZED)) {
 #ifdef SERIAL_DO_RESTART
-                       if (info->port.flags & ASYNC_HUP_NOTIFY)
+                       if (port->flags & ASYNC_HUP_NOTIFY)
                                retval = -EAGAIN;
                        else
                                retval = -ERESTARTSYS;
@@ -2141,11 +2152,9 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
                        break;
                }
 
-               serial_out(info, UART_ESI_CMD1, ESI_GET_UART_STAT);
-               if (serial_in(info, UART_ESI_STAT2) & UART_MSR_DCD)
-                       do_clocal = 1;
+               cd = tty_port_carrier_raised(port);
 
-               if (!(info->port.flags & ASYNC_CLOSING) &&
+               if (!(port->flags & ASYNC_CLOSING) &&
                    (do_clocal))
                        break;
                if (signal_pending(current)) {
@@ -2154,25 +2163,25 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
                }
 #ifdef SERIAL_DEBUG_OPEN
                printk(KERN_DEBUG "block_til_ready blocking: ttys%d, count = %d\n",
-                      info->line, info->port.count);
+                      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(&info->port.open_wait, &wait);
+       remove_wait_queue(&port->open_wait, &wait);
        if (!tty_hung_up_p(filp))
-               info->port.count++;
-       info->port.blocked_open--;
+               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, info->port.count);
+              info->line, port->count);
 #endif
        if (retval)
                return retval;
-       info->port.flags |= ASYNC_NORMAL_ACTIVE;
+       port->flags |= ASYNC_NORMAL_ACTIVE;
        return 0;
 }
 
@@ -2329,6 +2338,10 @@ static const struct tty_operations esp_ops = {
        .tiocmset = esp_tiocmset,
 };
 
+static const struct tty_port_operations esp_port_ops = {
+       .esp_carrier_raised,
+};
+
 /*
  * The serial driver boot-time initialization code!
  */
@@ -2415,6 +2428,8 @@ static int __init espserial_init(void)
        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);
@@ -2437,8 +2452,6 @@ static int __init espserial_init(void)
                info->config.flow_off = flow_off;
                info->config.pio_threshold = pio_threshold;
                info->next_port = ports;
-               init_waitqueue_head(&info->port.open_wait);
-               init_waitqueue_head(&info->port.close_wait);
                init_waitqueue_head(&info->delta_msr_wait);
                init_waitqueue_head(&info->break_wait);
                ports = info;
index c6090f84a2e46cf5f7c571bfd511c2c5b609cd57..9e4e569dc00ddf80b51c541e8fbe48182de2cc42 100644 (file)
@@ -376,7 +376,8 @@ static void gs_shutdown_port (struct gs_port *port)
 
 void gs_hangup(struct tty_struct *tty)
 {
-       struct gs_port   *port;
+       struct gs_port *port;
+       unsigned long flags;
 
        func_enter ();
 
@@ -386,9 +387,11 @@ void gs_hangup(struct tty_struct *tty)
                return;
 
        gs_shutdown_port (port);
+       spin_lock_irqsave(&port->port.lock, flags);
        port->port.flags &= ~(ASYNC_NORMAL_ACTIVE|GS_ACTIVE);
        port->port.tty = NULL;
        port->port.count = 0;
+       spin_unlock_irqrestore(&port->port.lock, flags);
 
        wake_up_interruptible(&port->port.open_wait);
        func_exit ();
@@ -397,7 +400,8 @@ void gs_hangup(struct tty_struct *tty)
 
 int gs_block_til_ready(void *port_, struct file * filp)
 {
-       struct gs_port *port = port_;
+       struct gs_port *gp = port_;
+       struct tty_port *port = &gp->port;
        DECLARE_WAITQUEUE(wait, current);
        int    retval;
        int    do_clocal = 0;
@@ -409,16 +413,16 @@ int gs_block_til_ready(void *port_, struct file * filp)
 
        if (!port) return 0;
 
-       tty = port->port.tty;
+       tty = port->tty;
 
        gs_dprintk (GS_DEBUG_BTR, "Entering gs_block_till_ready.\n"); 
        /*
         * 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->port.flags & ASYNC_CLOSING) {
-               interruptible_sleep_on(&port->port.close_wait);
-               if (port->port.flags & ASYNC_HUP_NOTIFY)
+       if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
+               interruptible_sleep_on(&port->close_wait);
+               if (port->flags & ASYNC_HUP_NOTIFY)
                        return -EAGAIN;
                else
                        return -ERESTARTSYS;
@@ -432,7 +436,7 @@ int gs_block_til_ready(void *port_, struct file * filp)
         */
        if ((filp->f_flags & O_NONBLOCK) ||
            (tty->flags & (1 << TTY_IO_ERROR))) {
-               port->port.flags |= ASYNC_NORMAL_ACTIVE;
+               port->flags |= ASYNC_NORMAL_ACTIVE;
                return 0;
        }
 
@@ -444,34 +448,34 @@ int gs_block_til_ready(void *port_, struct file * filp)
        /*
         * Block waiting for the carrier detect and the line to become
         * free (i.e., not in use by the callout).  While we are in
-        * this loop, port->port.count is dropped by one, so that
+        * this loop, port->count is dropped by one, so that
         * rs_close() knows when to free things.  We restore it upon
         * exit, either normal or abnormal.
         */
        retval = 0;
 
-       add_wait_queue(&port->port.open_wait, &wait);
+       add_wait_queue(&port->open_wait, &wait);
 
        gs_dprintk (GS_DEBUG_BTR, "after add waitq.\n"); 
-       spin_lock_irqsave(&port->driver_lock, flags);
+       spin_lock_irqsave(&port->lock, flags);
        if (!tty_hung_up_p(filp)) {
-               port->port.count--;
+               port->count--;
        }
-       spin_unlock_irqrestore(&port->driver_lock, flags);
-       port->port.blocked_open++;
+       port->blocked_open++;
+       spin_unlock_irqrestore(&port->lock, flags);
        while (1) {
-               CD = port->rd->get_CD (port);
+               CD = tty_port_carrier_raised(port);
                gs_dprintk (GS_DEBUG_BTR, "CD is now %d.\n", CD);
                set_current_state (TASK_INTERRUPTIBLE);
                if (tty_hung_up_p(filp) ||
-                   !(port->port.flags & ASYNC_INITIALIZED)) {
-                       if (port->port.flags & ASYNC_HUP_NOTIFY)
+                   !(port->flags & ASYNC_INITIALIZED)) {
+                       if (port->flags & ASYNC_HUP_NOTIFY)
                                retval = -EAGAIN;
                        else
                                retval = -ERESTARTSYS;
                        break;
                }
-               if (!(port->port.flags & ASYNC_CLOSING) &&
+               if (!(port->flags & ASYNC_CLOSING) &&
                    (do_clocal || CD))
                        break;
                gs_dprintk (GS_DEBUG_BTR, "signal_pending is now: %d (%lx)\n", 
@@ -483,19 +487,20 @@ int gs_block_til_ready(void *port_, struct file * filp)
                schedule();
        }
        gs_dprintk (GS_DEBUG_BTR, "Got out of the loop. (%d)\n",
-                   port->port.blocked_open);
+                   port->blocked_open);
        set_current_state (TASK_RUNNING);
-       remove_wait_queue(&port->port.open_wait, &wait);
+       remove_wait_queue(&port->open_wait, &wait);
+       
+       spin_lock_irqsave(&port->lock, flags);
        if (!tty_hung_up_p(filp)) {
-               port->port.count++;
+               port->count++;
        }
-       port->port.blocked_open--;
-       if (retval)
-               return retval;
-
-       port->port.flags |= ASYNC_NORMAL_ACTIVE;
+       port->blocked_open--;
+       if (retval == 0)
+               port->flags |= ASYNC_NORMAL_ACTIVE;
+       spin_unlock_irqrestore(&port->lock, flags);
        func_exit ();
-       return 0;
+       return retval;
 }                       
 
 
@@ -506,7 +511,7 @@ void gs_close(struct tty_struct * tty, struct file * filp)
        
        func_enter ();
 
-       port = (struct gs_port *) tty->driver_data;
+       port = tty->driver_data;
 
        if (!port) return;
 
@@ -516,10 +521,10 @@ void gs_close(struct tty_struct * tty, struct file * filp)
                port->port.tty = tty;
        }
 
-       spin_lock_irqsave(&port->driver_lock, flags);
+       spin_lock_irqsave(&port->port.lock, flags);
 
        if (tty_hung_up_p(filp)) {
-               spin_unlock_irqrestore(&port->driver_lock, flags);
+               spin_unlock_irqrestore(&port->port.lock, flags);
                if (port->rd->hungup)
                        port->rd->hungup (port);
                func_exit ();
@@ -538,7 +543,7 @@ void gs_close(struct tty_struct * tty, struct file * filp)
 
        if (port->port.count) {
                gs_dprintk(GS_DEBUG_CLOSE, "gs_close port %p: count: %d\n", port, port->port.count);
-               spin_unlock_irqrestore(&port->driver_lock, flags);
+               spin_unlock_irqrestore(&port->port.lock, flags);
                func_exit ();
                return;
        }
@@ -559,8 +564,10 @@ void gs_close(struct tty_struct * tty, struct file * filp)
         * line status register.
         */
 
+       spin_lock_irqsave(&port->driver_lock, flags);
        port->rd->disable_rx_interrupts (port);
        spin_unlock_irqrestore(&port->driver_lock, flags);
+       spin_unlock_irqrestore(&port->port.lock, flags);
 
        /* close has no way of returning "EINTR", so discard return value */
        if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
@@ -573,20 +580,25 @@ void gs_close(struct tty_struct * tty, struct file * filp)
        tty_ldisc_flush(tty);
        tty->closing = 0;
 
+       spin_lock_irqsave(&port->driver_lock, flags);
        port->event = 0;
        port->rd->close (port);
        port->rd->shutdown_port (port);
+       spin_unlock_irqrestore(&port->driver_lock, flags);
+
+       spin_lock_irqsave(&port->port.lock, flags);
        port->port.tty = NULL;
 
        if (port->port.blocked_open) {
                if (port->close_delay) {
-                       spin_unlock_irqrestore(&port->driver_lock, flags);
+                       spin_unlock_irqrestore(&port->port.lock, flags);
                        msleep_interruptible(jiffies_to_msecs(port->close_delay));
-                       spin_lock_irqsave(&port->driver_lock, flags);
+                       spin_lock_irqsave(&port->port.lock, flags);
                }
                wake_up_interruptible(&port->port.open_wait);
        }
        port->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING | ASYNC_INITIALIZED);
+       spin_unlock_irqrestore(&port->port.lock, flags);
        wake_up_interruptible(&port->port.close_wait);
 
        func_exit ();
index 0587b66d6fc7070225e7f493517cc30cac11cfdc..5a8a4c28c867fb67dd811afc0e728b2b2edf9cbc 100644 (file)
@@ -529,7 +529,7 @@ static void hvc_set_winsz(struct work_struct *work)
        tty = tty_kref_get(hp->tty);
        spin_unlock_irqrestore(&hp->lock, hvc_flags);
 
-       tty_do_resize(tty, tty, &ws);
+       tty_do_resize(tty, &ws);
        tty_kref_put(tty);
 }
 
index af055287271a6f4a27b9f15136d5ab5e96dee2cc..406f8742a260de8f57604718216609e35afcb6ea 100644 (file)
@@ -997,14 +997,14 @@ out:
 
 static int hvsi_write_room(struct tty_struct *tty)
 {
-       struct hvsi_struct *hp = (struct hvsi_struct *)tty->driver_data;
+       struct hvsi_struct *hp = tty->driver_data;
 
        return N_OUTBUF - hp->n_outbuf;
 }
 
 static int hvsi_chars_in_buffer(struct tty_struct *tty)
 {
-       struct hvsi_struct *hp = (struct hvsi_struct *)tty->driver_data;
+       struct hvsi_struct *hp = tty->driver_data;
 
        return hp->n_outbuf;
 }
@@ -1070,7 +1070,7 @@ out:
  */
 static void hvsi_throttle(struct tty_struct *tty)
 {
-       struct hvsi_struct *hp = (struct hvsi_struct *)tty->driver_data;
+       struct hvsi_struct *hp = tty->driver_data;
 
        pr_debug("%s\n", __func__);
 
@@ -1079,7 +1079,7 @@ static void hvsi_throttle(struct tty_struct *tty)
 
 static void hvsi_unthrottle(struct tty_struct *tty)
 {
-       struct hvsi_struct *hp = (struct hvsi_struct *)tty->driver_data;
+       struct hvsi_struct *hp = tty->driver_data;
        unsigned long flags;
        int shouldflip = 0;
 
@@ -1100,7 +1100,7 @@ static void hvsi_unthrottle(struct tty_struct *tty)
 
 static int hvsi_tiocmget(struct tty_struct *tty, struct file *file)
 {
-       struct hvsi_struct *hp = (struct hvsi_struct *)tty->driver_data;
+       struct hvsi_struct *hp = tty->driver_data;
 
        hvsi_get_mctrl(hp);
        return hp->mctrl;
@@ -1109,7 +1109,7 @@ static int hvsi_tiocmget(struct tty_struct *tty, struct file *file)
 static int hvsi_tiocmset(struct tty_struct *tty, struct file *file,
                unsigned int set, unsigned int clear)
 {
-       struct hvsi_struct *hp = (struct hvsi_struct *)tty->driver_data;
+       struct hvsi_struct *hp = tty->driver_data;
        unsigned long flags;
        uint16_t new_mctrl;
 
index 04e4549299baf5cb12e0b003768bea34a7b5232e..24aa6e88e223d5772649182d878342224749c3c1 100644 (file)
@@ -328,11 +328,13 @@ static inline void drop_rts(struct isi_port *port)
 }
 
 /* card->lock MUST NOT be held */
-static inline void raise_dtr_rts(struct isi_port *port)
+
+static void isicom_raise_dtr_rts(struct tty_port *port)
 {
-       struct isi_board *card = port->card;
+       struct isi_port *ip = container_of(port, struct isi_port, port);
+       struct isi_board *card = ip->card;
        unsigned long base = card->base;
-       u16 channel = port->channel;
+       u16 channel = ip->channel;
 
        if (!lock_card(card))
                return;
@@ -340,7 +342,7 @@ static inline void raise_dtr_rts(struct isi_port *port)
        outw(0x8000 | (channel << card->shift_count) | 0x02, base);
        outw(0x0f04, base);
        InterruptTheCard(base);
-       port->status |= (ISI_DTR | ISI_RTS);
+       ip->status |= (ISI_DTR | ISI_RTS);
        unlock_card(card);
 }
 
@@ -830,80 +832,10 @@ static int isicom_setup_port(struct tty_struct *tty)
        return 0;
 }
 
-static int block_til_ready(struct tty_struct *tty, struct file *filp,
-       struct isi_port *port)
+static int isicom_carrier_raised(struct tty_port *port)
 {
-       struct isi_board *card = port->card;
-       int do_clocal = 0, retval;
-       unsigned long flags;
-       DECLARE_WAITQUEUE(wait, current);
-
-       /* block if port is in the process of being closed */
-
-       if (tty_hung_up_p(filp) || port->port.flags & ASYNC_CLOSING) {
-               pr_dbg("block_til_ready: close in progress.\n");
-               interruptible_sleep_on(&port->port.close_wait);
-               if (port->port.flags & ASYNC_HUP_NOTIFY)
-                       return -EAGAIN;
-               else
-                       return -ERESTARTSYS;
-       }
-
-       /* if non-blocking mode is set ... */
-
-       if ((filp->f_flags & O_NONBLOCK) ||
-                       (tty->flags & (1 << TTY_IO_ERROR))) {
-               pr_dbg("block_til_ready: non-block mode.\n");
-               port->port.flags |= ASYNC_NORMAL_ACTIVE;
-               return 0;
-       }
-
-       if (C_CLOCAL(tty))
-               do_clocal = 1;
-
-       /* block waiting for DCD to be asserted, and while
-                                               callout dev is busy */
-       retval = 0;
-       add_wait_queue(&port->port.open_wait, &wait);
-
-       spin_lock_irqsave(&card->card_lock, flags);
-       if (!tty_hung_up_p(filp))
-               port->port.count--;
-       port->port.blocked_open++;
-       spin_unlock_irqrestore(&card->card_lock, flags);
-
-       while (1) {
-               raise_dtr_rts(port);
-
-               set_current_state(TASK_INTERRUPTIBLE);
-               if (tty_hung_up_p(filp) || !(port->port.flags & ASYNC_INITIALIZED)) {
-                       if (port->port.flags & ASYNC_HUP_NOTIFY)
-                               retval = -EAGAIN;
-                       else
-                               retval = -ERESTARTSYS;
-                       break;
-               }
-               if (!(port->port.flags & ASYNC_CLOSING) &&
-                               (do_clocal || (port->status & ISI_DCD))) {
-                       break;
-               }
-               if (signal_pending(current)) {
-                       retval = -ERESTARTSYS;
-                       break;
-               }
-               schedule();
-       }
-       set_current_state(TASK_RUNNING);
-       remove_wait_queue(&port->port.open_wait, &wait);
-       spin_lock_irqsave(&card->card_lock, flags);
-       if (!tty_hung_up_p(filp))
-               port->port.count++;
-       port->port.blocked_open--;
-       spin_unlock_irqrestore(&card->card_lock, flags);
-       if (retval)
-               return retval;
-       port->port.flags |= ASYNC_NORMAL_ACTIVE;
-       return 0;
+       struct isi_port *ip = container_of(port, struct isi_port, port);
+       return (ip->status & ISI_DCD)?1 : 0;
 }
 
 static int isicom_open(struct tty_struct *tty, struct file *filp)
@@ -932,12 +864,13 @@ static int isicom_open(struct tty_struct *tty, struct file *filp)
 
        isicom_setup_board(card);
 
+       /* FIXME: locking on port.count etc */
        port->port.count++;
        tty->driver_data = port;
        tty_port_tty_set(&port->port, tty);
        error = isicom_setup_port(tty);
        if (error == 0)
-               error = block_til_ready(tty, filp, port);
+               error = tty_port_block_til_ready(&port->port, tty, filp);
        return error;
 }
 
@@ -1012,76 +945,30 @@ static void isicom_flush_buffer(struct tty_struct *tty)
 
 static void isicom_close(struct tty_struct *tty, struct file *filp)
 {
-       struct isi_port *port = tty->driver_data;
+       struct isi_port *ip = tty->driver_data;
+       struct tty_port *port = &ip->port;
        struct isi_board *card;
        unsigned long flags;
 
-       if (!port)
-               return;
-       card = port->card;
-       if (isicom_paranoia_check(port, tty->name, "isicom_close"))
-               return;
-
-       pr_dbg("Close start!!!.\n");
-
-       spin_lock_irqsave(&card->card_lock, flags);
-       if (tty_hung_up_p(filp)) {
-               spin_unlock_irqrestore(&card->card_lock, flags);
-               return;
-       }
-
-       if (tty->count == 1 && port->port.count != 1) {
-               printk(KERN_WARNING "ISICOM:(0x%lx) isicom_close: bad port "
-                       "count tty->count = 1 port count = %d.\n",
-                       card->base, port->port.count);
-               port->port.count = 1;
-       }
-       if (--port->port.count < 0) {
-               printk(KERN_WARNING "ISICOM:(0x%lx) isicom_close: bad port "
-                       "count for channel%d = %d", card->base, port->channel,
-                       port->port.count);
-               port->port.count = 0;
-       }
+       BUG_ON(!ip);
 
-       if (port->port.count) {
-               spin_unlock_irqrestore(&card->card_lock, flags);
+       card = ip->card;
+       if (isicom_paranoia_check(ip, tty->name, "isicom_close"))
                return;
-       }
-       port->port.flags |= ASYNC_CLOSING;
-       tty->closing = 1;
-       spin_unlock_irqrestore(&card->card_lock, flags);
 
-       if (port->port.closing_wait != ASYNC_CLOSING_WAIT_NONE)
-               tty_wait_until_sent(tty, port->port.closing_wait);
        /* indicate to the card that no more data can be received
           on this port */
        spin_lock_irqsave(&card->card_lock, flags);
-       if (port->port.flags & ASYNC_INITIALIZED) {
-               card->port_status &= ~(1 << port->channel);
+       if (port->flags & ASYNC_INITIALIZED) {
+               card->port_status &= ~(1 << ip->channel);
                outw(card->port_status, card->base + 0x02);
        }
-       isicom_shutdown_port(port);
+       isicom_shutdown_port(ip);
        spin_unlock_irqrestore(&card->card_lock, flags);
 
        isicom_flush_buffer(tty);
-       tty_ldisc_flush(tty);
-
-       spin_lock_irqsave(&card->card_lock, flags);
-       tty->closing = 0;
-
-       if (port->port.blocked_open) {
-               spin_unlock_irqrestore(&card->card_lock, flags);
-               if (port->port.close_delay) {
-                       pr_dbg("scheduling until time out.\n");
-                       msleep_interruptible(
-                               jiffies_to_msecs(port->port.close_delay));
-               }
-               spin_lock_irqsave(&card->card_lock, flags);
-               wake_up_interruptible(&port->port.open_wait);
-       }
-       port->port.flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
-       wake_up_interruptible(&port->port.close_wait);
-       spin_unlock_irqrestore(&card->card_lock, flags);
+       
+       tty_port_close_end(port, tty);
 }
 
 /* write et all */
@@ -1420,10 +1307,7 @@ static void isicom_hangup(struct tty_struct *tty)
        isicom_shutdown_port(port);
        spin_unlock_irqrestore(&port->card->card_lock, flags);
 
-       port->port.count = 0;
-       port->port.flags &= ~ASYNC_NORMAL_ACTIVE;
-       tty_port_tty_set(&port->port, NULL);
-       wake_up_interruptible(&port->port.open_wait);
+       tty_port_hangup(&port->port);
 }
 
 
@@ -1452,6 +1336,11 @@ static const struct tty_operations isicom_ops = {
        .break_ctl              = isicom_send_break,
 };
 
+static const struct tty_port_operations isicom_port_ops = {
+       .carrier_raised         = isicom_carrier_raised,
+       .raise_dtr_rts          = isicom_raise_dtr_rts,
+};
+
 static int __devinit reset_card(struct pci_dev *pdev,
        const unsigned int card, unsigned int *signature)
 {
@@ -1794,6 +1683,7 @@ static int __init isicom_init(void)
                spin_lock_init(&isi_card[idx].card_lock);
                for (channel = 0; channel < 16; channel++, port++) {
                        tty_port_init(&port->port);
+                       port->port.ops = &isicom_port_ops;
                        port->magic = ISICOM_MAGIC;
                        port->card = &isi_card[idx];
                        port->channel = channel;
index 4b10770fa9377e2ed316abaf0bfdada41adb5044..5c3dc6b8411c88d62ec800f082678dc6f66ec3d8 100644 (file)
@@ -151,7 +151,7 @@ static char *stli_drvversion = "5.6.0";
 static char    *stli_serialname = "ttyE";
 
 static struct tty_driver       *stli_serial;
-
+static const struct tty_port_operations stli_port_ops;
 
 #define        STLI_TXBUFSIZE          4096
 
@@ -626,8 +626,6 @@ static int  stli_hostcmd(struct stlibrd *brdp, struct stliport *portp);
 static int     stli_initopen(struct tty_struct *tty, struct stlibrd *brdp, struct stliport *portp);
 static int     stli_rawopen(struct stlibrd *brdp, struct stliport *portp, unsigned long arg, int wait);
 static int     stli_rawclose(struct stlibrd *brdp, struct stliport *portp, unsigned long arg, int wait);
-static int     stli_waitcarrier(struct tty_struct *tty, struct stlibrd *brdp,
-                               struct stliport *portp, struct file *filp);
 static int     stli_setport(struct tty_struct *tty);
 static int     stli_cmdwait(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback);
 static void    stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback);
@@ -769,7 +767,7 @@ static int stli_parsebrd(struct stlconf *confp, char **argp)
                        break;
        }
        if (i == ARRAY_SIZE(stli_brdstr)) {
-               printk("STALLION: unknown board name, %s?\n", argp[0]);
+               printk(KERN_WARNING "istallion: unknown board name, %s?\n", argp[0]);
                return 0;
        }
 
@@ -787,6 +785,7 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
 {
        struct stlibrd *brdp;
        struct stliport *portp;
+       struct tty_port *port;
        unsigned int minordev, brdnr, portnr;
        int rc;
 
@@ -808,30 +807,19 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
                return -ENODEV;
        if (portp->devnr < 1)
                return -ENODEV;
-
-
-/*
- *     Check if this port is in the middle of closing. If so then wait
- *     until it is closed then return error status based on flag settings.
- *     The sleep here does not need interrupt protection since the wakeup
- *     for it is done with the same context.
- */
-       if (portp->port.flags & ASYNC_CLOSING) {
-               interruptible_sleep_on(&portp->port.close_wait);
-               if (portp->port.flags & ASYNC_HUP_NOTIFY)
-                       return -EAGAIN;
-               return -ERESTARTSYS;
-       }
+       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(&portp->port, tty);
+       tty_port_tty_set(port, tty);
        tty->driver_data = portp;
-       portp->port.count++;
+       port->count++;
 
        wait_event_interruptible(portp->raw_wait,
                        !test_bit(ST_INITIALIZING, &portp->state));
@@ -841,7 +829,8 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
        if ((portp->port.flags & ASYNC_INITIALIZED) == 0) {
                set_bit(ST_INITIALIZING, &portp->state);
                if ((rc = stli_initopen(tty, brdp, portp)) >= 0) {
-                       portp->port.flags |= ASYNC_INITIALIZED;
+                       /* Locking */
+                       port->flags |= ASYNC_INITIALIZED;
                        clear_bit(TTY_IO_ERROR, &tty->flags);
                }
                clear_bit(ST_INITIALIZING, &portp->state);
@@ -849,31 +838,7 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
                if (rc < 0)
                        return rc;
        }
-
-/*
- *     Check if this port is in the middle of closing. If so then wait
- *     until it is closed then return error status, based on flag settings.
- *     The sleep here does not need interrupt protection since the wakeup
- *     for it is done with the same context.
- */
-       if (portp->port.flags & ASYNC_CLOSING) {
-               interruptible_sleep_on(&portp->port.close_wait);
-               if (portp->port.flags & ASYNC_HUP_NOTIFY)
-                       return -EAGAIN;
-               return -ERESTARTSYS;
-       }
-
-/*
- *     Based on type of open being done check if it can overlap with any
- *     previous opens still in effect. If we are a normal serial device
- *     then also we might have to wait for carrier.
- */
-       if (!(filp->f_flags & O_NONBLOCK)) {
-               if ((rc = stli_waitcarrier(tty, brdp, portp, filp)) != 0)
-                       return rc;
-       }
-       portp->port.flags |= ASYNC_NORMAL_ACTIVE;
-       return 0;
+       return tty_port_block_til_ready(&portp->port, tty, filp);
 }
 
 /*****************************************************************************/
@@ -882,25 +847,16 @@ static void stli_close(struct tty_struct *tty, struct file *filp)
 {
        struct stlibrd *brdp;
        struct stliport *portp;
+       struct tty_port *port;
        unsigned long flags;
 
        portp = tty->driver_data;
        if (portp == NULL)
                return;
+       port = &portp->port;
 
-       spin_lock_irqsave(&stli_lock, flags);
-       if (tty_hung_up_p(filp)) {
-               spin_unlock_irqrestore(&stli_lock, flags);
-               return;
-       }
-       if ((tty->count == 1) && (portp->port.count != 1))
-               portp->port.count = 1;
-       if (portp->port.count-- > 1) {
-               spin_unlock_irqrestore(&stli_lock, flags);
+       if (tty_port_close_start(port, tty, filp) == 0)
                return;
-       }
-
-       portp->port.flags |= ASYNC_CLOSING;
 
 /*
  *     May want to wait for data to drain before closing. The BUSY flag
@@ -908,15 +864,19 @@ static void stli_close(struct tty_struct *tty, struct file *filp)
  *     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);
-       tty->closing = 1;
        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);
 
-       portp->port.flags &= ~ASYNC_INITIALIZED;
+       /* FIXME: port locking here needs attending to */
+       port->flags &= ~ASYNC_INITIALIZED;
+
        brdp = stli_brds[portp->brdnr];
        stli_rawclose(brdp, portp, 0, 0);
        if (tty->termios->c_cflag & HUPCL) {
@@ -934,17 +894,8 @@ static void stli_close(struct tty_struct *tty, struct file *filp)
        set_bit(ST_DOFLUSHRX, &portp->state);
        stli_flushbuffer(tty);
 
-       tty->closing = 0;
-       tty_port_tty_set(&portp->port, NULL);
-
-       if (portp->openwaitcnt) {
-               if (portp->close_delay)
-                       msleep_interruptible(jiffies_to_msecs(portp->close_delay));
-               wake_up_interruptible(&portp->port.open_wait);
-       }
-
-       portp->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
-       wake_up_interruptible(&portp->port.close_wait);
+       tty_port_close_end(port, tty);
+       tty_port_tty_set(port, NULL);
 }
 
 /*****************************************************************************/
@@ -1183,62 +1134,23 @@ static int stli_setport(struct tty_struct *tty)
 
 /*****************************************************************************/
 
-/*
- *     Possibly need to wait for carrier (DCD signal) to come high. Say
- *     maybe because if we are clocal then we don't need to wait...
- */
-
-static int stli_waitcarrier(struct tty_struct *tty, struct stlibrd *brdp,
-                               struct stliport *portp, struct file *filp)
+static int stli_carrier_raised(struct tty_port *port)
 {
-       unsigned long flags;
-       int rc, doclocal;
-
-       rc = 0;
-       doclocal = 0;
-
-       if (tty->termios->c_cflag & CLOCAL)
-               doclocal++;
-
-       spin_lock_irqsave(&stli_lock, flags);
-       portp->openwaitcnt++;
-       if (! tty_hung_up_p(filp))
-               portp->port.count--;
-       spin_unlock_irqrestore(&stli_lock, flags);
-
-       for (;;) {
-               stli_mkasysigs(&portp->asig, 1, 1);
-               if ((rc = stli_cmdwait(brdp, portp, A_SETSIGNALS,
-                   &portp->asig, sizeof(asysigs_t), 0)) < 0)
-                       break;
-               if (tty_hung_up_p(filp) ||
-                   ((portp->port.flags & ASYNC_INITIALIZED) == 0)) {
-                       if (portp->port.flags & ASYNC_HUP_NOTIFY)
-                               rc = -EBUSY;
-                       else
-                               rc = -ERESTARTSYS;
-                       break;
-               }
-               if (((portp->port.flags & ASYNC_CLOSING) == 0) &&
-                   (doclocal || (portp->sigs & TIOCM_CD))) {
-                       break;
-               }
-               if (signal_pending(current)) {
-                       rc = -ERESTARTSYS;
-                       break;
-               }
-               interruptible_sleep_on(&portp->port.open_wait);
-       }
-
-       spin_lock_irqsave(&stli_lock, flags);
-       if (! tty_hung_up_p(filp))
-               portp->port.count++;
-       portp->openwaitcnt--;
-       spin_unlock_irqrestore(&stli_lock, flags);
+       struct stliport *portp = container_of(port, struct stliport, port);
+       return (portp->sigs & TIOCM_CD) ? 1 : 0;
+}
 
-       return rc;
+static void stli_raise_dtr_rts(struct tty_port *port)
+{
+       struct stliport *portp = container_of(port, struct stliport, port);
+       struct stlibrd *brdp = stli_brds[portp->brdnr];
+       stli_mkasysigs(&portp->asig, 1, 1);
+       if (stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig,
+               sizeof(asysigs_t), 0) < 0)
+                       printk(KERN_WARNING "istallion: dtr raise failed.\n");
 }
 
+
 /*****************************************************************************/
 
 /*
@@ -1550,7 +1462,7 @@ static int stli_getserial(struct stliport *portp, struct serial_struct __user *s
        sio.irq = 0;
        sio.flags = portp->port.flags;
        sio.baud_base = portp->baud_base;
-       sio.close_delay = portp->close_delay;
+       sio.close_delay = portp->port.close_delay;
        sio.closing_wait = portp->closing_wait;
        sio.custom_divisor = portp->custom_divisor;
        sio.xmit_fifo_size = 0;
@@ -1582,7 +1494,7 @@ static int stli_setserial(struct tty_struct *tty, struct serial_struct __user *s
                return -EFAULT;
        if (!capable(CAP_SYS_ADMIN)) {
                if ((sio.baud_base != portp->baud_base) ||
-                   (sio.close_delay != portp->close_delay) ||
+                   (sio.close_delay != portp->port.close_delay) ||
                    ((sio.flags & ~ASYNC_USR_MASK) !=
                    (portp->port.flags & ~ASYNC_USR_MASK)))
                        return -EPERM;
@@ -1591,7 +1503,7 @@ static int stli_setserial(struct tty_struct *tty, struct serial_struct __user *s
        portp->port.flags = (portp->port.flags & ~ASYNC_USR_MASK) |
                (sio.flags & ASYNC_USR_MASK);
        portp->baud_base = sio.baud_base;
-       portp->close_delay = sio.close_delay;
+       portp->port.close_delay = sio.close_delay;
        portp->closing_wait = sio.closing_wait;
        portp->custom_divisor = sio.custom_divisor;
 
@@ -1821,6 +1733,7 @@ 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;
@@ -1831,8 +1744,11 @@ static void stli_hangup(struct tty_struct *tty)
        brdp = stli_brds[portp->brdnr];
        if (brdp == NULL)
                return;
+       port = &portp->port;
 
-       portp->port.flags &= ~ASYNC_INITIALIZED;
+       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);
@@ -1853,12 +1769,9 @@ static void stli_hangup(struct tty_struct *tty)
        clear_bit(ST_TXBUSY, &portp->state);
        clear_bit(ST_RXSTOP, &portp->state);
        set_bit(TTY_IO_ERROR, &tty->flags);
-       tty_port_tty_set(&portp->port, NULL);
-       portp->port.flags &= ~ASYNC_NORMAL_ACTIVE;
-       portp->port.count = 0;
        spin_unlock_irqrestore(&stli_lock, flags);
 
-       wake_up_interruptible(&portp->port.open_wait);
+       tty_port_hangup(port);
 }
 
 /*****************************************************************************/
@@ -2132,7 +2045,7 @@ static void __stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigne
        unsigned char __iomem *bits;
 
        if (test_bit(ST_CMDING, &portp->state)) {
-               printk(KERN_ERR "STALLION: command already busy, cmd=%x!\n",
+               printk(KERN_ERR "istallion: command already busy, cmd=%x!\n",
                                (int) cmd);
                return;
        }
@@ -2692,16 +2605,17 @@ static int stli_initports(struct stlibrd *brdp)
        for (i = 0, panelnr = 0, panelport = 0; (i < brdp->nrports); i++) {
                portp = kzalloc(sizeof(struct stliport), GFP_KERNEL);
                if (!portp) {
-                       printk("STALLION: failed to allocate port structure\n");
+                       printk(KERN_WARNING "istallion: failed to allocate port structure\n");
                        continue;
                }
                tty_port_init(&portp->port);
+               portp->port.ops = &stli_port_ops;
                portp->magic = STLI_PORTMAGIC;
                portp->portnr = i;
                portp->brdnr = brdp->brdnr;
                portp->panelnr = panelnr;
                portp->baud_base = STL_BAUDBASE;
-               portp->close_delay = STL_CLOSEDELAY;
+               portp->port.close_delay = STL_CLOSEDELAY;
                portp->closing_wait = 30 * HZ;
                init_waitqueue_head(&portp->port.open_wait);
                init_waitqueue_head(&portp->port.close_wait);
@@ -2758,7 +2672,7 @@ static void __iomem *stli_ecpgetmemptr(struct stlibrd *brdp, unsigned long offse
        unsigned char val;
 
        if (offset > brdp->memsize) {
-               printk(KERN_ERR "STALLION: shared memory pointer=%x out of "
+               printk(KERN_ERR "istallion: shared memory pointer=%x out of "
                                "range at line=%d(%d), brd=%d\n",
                        (int) offset, line, __LINE__, brdp->brdnr);
                ptr = NULL;
@@ -2832,7 +2746,7 @@ static void __iomem *stli_ecpeigetmemptr(struct stlibrd *brdp, unsigned long off
        unsigned char   val;
 
        if (offset > brdp->memsize) {
-               printk(KERN_ERR "STALLION: shared memory pointer=%x out of "
+               printk(KERN_ERR "istallion: shared memory pointer=%x out of "
                                "range at line=%d(%d), brd=%d\n",
                        (int) offset, line, __LINE__, brdp->brdnr);
                ptr = NULL;
@@ -2884,7 +2798,7 @@ static void __iomem *stli_ecpmcgetmemptr(struct stlibrd *brdp, unsigned long off
        unsigned char val;
 
        if (offset > brdp->memsize) {
-               printk(KERN_ERR "STALLION: shared memory pointer=%x out of "
+               printk(KERN_ERR "istallion: shared memory pointer=%x out of "
                                "range at line=%d(%d), brd=%d\n",
                        (int) offset, line, __LINE__, brdp->brdnr);
                ptr = NULL;
@@ -2929,7 +2843,7 @@ static void __iomem *stli_ecppcigetmemptr(struct stlibrd *brdp, unsigned long of
        unsigned char   val;
 
        if (offset > brdp->memsize) {
-               printk(KERN_ERR "STALLION: shared memory pointer=%x out of "
+               printk(KERN_ERR "istallion: shared memory pointer=%x out of "
                                "range at line=%d(%d), board=%d\n",
                                (int) offset, line, __LINE__, brdp->brdnr);
                ptr = NULL;
@@ -2994,7 +2908,7 @@ static void __iomem *stli_onbgetmemptr(struct stlibrd *brdp, unsigned long offse
        void __iomem *ptr;
 
        if (offset > brdp->memsize) {
-               printk(KERN_ERR "STALLION: shared memory pointer=%x out of "
+               printk(KERN_ERR "istallion: shared memory pointer=%x out of "
                                "range at line=%d(%d), brd=%d\n",
                                (int) offset, line, __LINE__, brdp->brdnr);
                ptr = NULL;
@@ -3060,7 +2974,7 @@ static void __iomem *stli_onbegetmemptr(struct stlibrd *brdp, unsigned long offs
        unsigned char val;
 
        if (offset > brdp->memsize) {
-               printk(KERN_ERR "STALLION: shared memory pointer=%x out of "
+               printk(KERN_ERR "istallion: shared memory pointer=%x out of "
                                "range at line=%d(%d), brd=%d\n",
                        (int) offset, line, __LINE__, brdp->brdnr);
                ptr = NULL;
@@ -3499,7 +3413,7 @@ static int stli_startbrd(struct stlibrd *brdp)
 #endif
 
        if (nrdevs < (brdp->nrports + 1)) {
-               printk(KERN_ERR "STALLION: slave failed to allocate memory for "
+               printk(KERN_ERR "istallion: slave failed to allocate memory for "
                                "all devices, devices=%d\n", nrdevs);
                brdp->nrports = nrdevs - 1;
        }
@@ -3509,13 +3423,13 @@ static int stli_startbrd(struct stlibrd *brdp)
        brdp->bitsize = (nrdevs + 7) / 8;
        memoff = readl(&hdrp->memp);
        if (memoff > brdp->memsize) {
-               printk(KERN_ERR "STALLION: corrupted shared memory region?\n");
+               printk(KERN_ERR "istallion: corrupted shared memory region?\n");
                rc = -EIO;
                goto stli_donestartup;
        }
        memp = (cdkmem_t __iomem *) EBRDGETMEMPTR(brdp, memoff);
        if (readw(&memp->dtype) != TYP_ASYNCTRL) {
-               printk(KERN_ERR "STALLION: no slave control device found\n");
+               printk(KERN_ERR "istallion: no slave control device found\n");
                goto stli_donestartup;
        }
        memp++;
@@ -3600,7 +3514,7 @@ static int __devinit stli_brdinit(struct stlibrd *brdp)
                retval = stli_initonb(brdp);
                break;
        default:
-               printk(KERN_ERR "STALLION: board=%d is unknown board "
+               printk(KERN_ERR "istallion: board=%d is unknown board "
                                "type=%d\n", brdp->brdnr, brdp->brdtype);
                retval = -ENODEV;
        }
@@ -3609,7 +3523,7 @@ static int __devinit stli_brdinit(struct stlibrd *brdp)
                return retval;
 
        stli_initports(brdp);
-       printk(KERN_INFO "STALLION: %s found, board=%d io=%x mem=%x "
+       printk(KERN_INFO "istallion: %s found, board=%d io=%x mem=%x "
                "nrpanels=%d nrports=%d\n", stli_brdnames[brdp->brdtype],
                brdp->brdnr, brdp->iobase, (int) brdp->memaddr,
                brdp->nrpanels, brdp->nrports);
@@ -3703,7 +3617,7 @@ static int stli_eisamemprobe(struct stlibrd *brdp)
        if (! foundit) {
                brdp->memaddr = 0;
                brdp->membase = NULL;
-               printk(KERN_ERR "STALLION: failed to probe shared memory "
+               printk(KERN_ERR "istallion: failed to probe shared memory "
                                "region for %s in EISA slot=%d\n",
                        stli_brdnames[brdp->brdtype], (brdp->iobase >> 12));
                return -ENODEV;
@@ -3848,7 +3762,7 @@ static int __devinit stli_pciprobe(struct pci_dev *pdev,
        mutex_lock(&stli_brdslock);
        brdnr = stli_getbrdnr();
        if (brdnr < 0) {
-               printk(KERN_INFO "STALLION: too many boards found, "
+               printk(KERN_INFO "istallion: too many boards found, "
                        "maximum supported %d\n", STL_MAXBRDS);
                mutex_unlock(&stli_brdslock);
                retval = -EIO;
@@ -3920,7 +3834,7 @@ static struct stlibrd *stli_allocbrd(void)
 
        brdp = kzalloc(sizeof(struct stlibrd), GFP_KERNEL);
        if (!brdp) {
-               printk(KERN_ERR "STALLION: failed to allocate memory "
+               printk(KERN_ERR "istallion: failed to allocate memory "
                                "(size=%Zd)\n", sizeof(struct stlibrd));
                return NULL;
        }
@@ -4518,6 +4432,11 @@ static const struct tty_operations stli_ops = {
        .tiocmset = stli_tiocmset,
 };
 
+static const struct tty_port_operations stli_port_ops = {
+       .carrier_raised = stli_carrier_raised,
+       .raise_dtr_rts = stli_raise_dtr_rts,
+};
+
 /*****************************************************************************/
 /*
  *     Loadable module initialization stuff.
@@ -4554,7 +4473,7 @@ static int __init istallion_module_init(void)
 
        stli_txcookbuf = kmalloc(STLI_TXBUFSIZE, GFP_KERNEL);
        if (!stli_txcookbuf) {
-               printk(KERN_ERR "STALLION: failed to allocate memory "
+               printk(KERN_ERR "istallion: failed to allocate memory "
                                "(size=%d)\n", STLI_TXBUFSIZE);
                retval = -ENOMEM;
                goto err;
@@ -4579,7 +4498,7 @@ static int __init istallion_module_init(void)
 
        retval = tty_register_driver(stli_serial);
        if (retval) {
-               printk(KERN_ERR "STALLION: failed to register serial driver\n");
+               printk(KERN_ERR "istallion: failed to register serial driver\n");
                goto err_ttyput;
        }
 
@@ -4593,7 +4512,7 @@ static int __init istallion_module_init(void)
  */
        retval = register_chrdev(STL_SIOMEMMAJOR, "staliomem", &stli_fsiomem);
        if (retval) {
-               printk(KERN_ERR "STALLION: failed to register serial memory "
+               printk(KERN_ERR "istallion: failed to register serial memory "
                                "device\n");
                goto err_deinit;
        }
index 12d327a2c9ba72cadd471670f6300cca3e9a1ad0..8b0da97d5293b58f09b267131455e714b5d8344c 100644 (file)
@@ -206,6 +206,7 @@ static void moxa_poll(unsigned long);
 static void moxa_set_tty_param(struct tty_struct *, struct ktermios *);
 static void moxa_setup_empty_event(struct tty_struct *);
 static void moxa_shut_down(struct tty_struct *);
+static int moxa_carrier_raised(struct tty_port *);
 /*
  * moxa board interface functions:
  */
@@ -405,6 +406,10 @@ static const struct tty_operations moxa_ops = {
        .tiocmset = moxa_tiocmset,
 };
 
+static const struct tty_port_operations moxa_port_ops = {
+       .carrier_raised = moxa_carrier_raised,
+};
+
 static struct tty_driver *moxaDriver;
 static DEFINE_TIMER(moxaTimer, moxa_poll, 0, 0);
 static DEFINE_SPINLOCK(moxa_lock);
@@ -826,6 +831,7 @@ static int moxa_init_board(struct moxa_board_conf *brd, struct device *dev)
 
        for (i = 0, p = brd->ports; i < MAX_PORTS_PER_BOARD; i++, p++) {
                tty_port_init(&p->port);
+               p->port.ops = &moxa_port_ops;
                p->type = PORT_16550A;
                p->cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
        }
@@ -1115,15 +1121,27 @@ static void moxa_close_port(struct tty_struct *tty)
        tty_port_tty_set(&ch->port, NULL);
 }
 
+static int moxa_carrier_raised(struct tty_port *port)
+{
+       struct moxa_port *ch = container_of(port, struct moxa_port, port);
+       int dcd;
+
+       spin_lock_bh(&moxa_lock);
+       dcd = ch->DCDState;
+       spin_unlock_bh(&moxa_lock);
+       return dcd;
+}
+
 static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp,
                            struct moxa_port *ch)
 {
+       struct tty_port *port = &ch->port;
        DEFINE_WAIT(wait);
        int retval = 0;
        u8 dcd;
 
        while (1) {
-               prepare_to_wait(&ch->port.open_wait, &wait, TASK_INTERRUPTIBLE);
+               prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE);
                if (tty_hung_up_p(filp)) {
 #ifdef SERIAL_DO_RESTART
                        retval = -ERESTARTSYS;
@@ -1132,9 +1150,7 @@ static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp,
 #endif
                        break;
                }
-               spin_lock_bh(&moxa_lock);
-               dcd = ch->DCDState;
-               spin_unlock_bh(&moxa_lock);
+               dcd = tty_port_carrier_raised(port);
                if (dcd)
                        break;
 
@@ -1144,7 +1160,7 @@ static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp,
                }
                schedule();
        }
-       finish_wait(&ch->port.open_wait, &wait);
+       finish_wait(&port->open_wait, &wait);
 
        return retval;
 }
index 047766915411315d076ca35edcde38f1b9b77e0a..402c9f217f83a3853f62b5a09401ab8ab0d8f3a3 100644 (file)
@@ -541,74 +541,21 @@ static unsigned char mxser_get_msr(int baseaddr, int mode, int port)
        return status;
 }
 
-static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp,
-               struct mxser_port *port)
+static int mxser_carrier_raised(struct tty_port *port)
 {
-       DECLARE_WAITQUEUE(wait, current);
-       int retval;
-       int do_clocal = 0;
-       unsigned long flags;
-
-       /*
-        * 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) ||
-                       test_bit(TTY_IO_ERROR, &tty->flags)) {
-               port->port.flags |= ASYNC_NORMAL_ACTIVE;
-               return 0;
-       }
+       struct mxser_port *mp = container_of(port, struct mxser_port, port);
+       return (inb(mp->ioaddr + UART_MSR) & UART_MSR_DCD)?1:0;
+}
 
-       if (tty->termios->c_cflag & CLOCAL)
-               do_clocal = 1;
+static void mxser_raise_dtr_rts(struct tty_port *port)
+{
+       struct mxser_port *mp = container_of(port, struct mxser_port, port);
+       unsigned long flags;
 
-       /*
-        * 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->port.count is dropped by one, so that
-        * mxser_close() knows when to free things.  We restore it upon
-        * exit, either normal or abnormal.
-        */
-       retval = 0;
-       add_wait_queue(&port->port.open_wait, &wait);
-
-       spin_lock_irqsave(&port->slock, flags);
-       if (!tty_hung_up_p(filp))
-               port->port.count--;
-       spin_unlock_irqrestore(&port->slock, flags);
-       port->port.blocked_open++;
-       while (1) {
-               spin_lock_irqsave(&port->slock, flags);
-               outb(inb(port->ioaddr + UART_MCR) |
-                       UART_MCR_DTR | UART_MCR_RTS, port->ioaddr + UART_MCR);
-               spin_unlock_irqrestore(&port->slock, flags);
-               set_current_state(TASK_INTERRUPTIBLE);
-               if (tty_hung_up_p(filp) || !(port->port.flags & ASYNC_INITIALIZED)) {
-                       if (port->port.flags & ASYNC_HUP_NOTIFY)
-                               retval = -EAGAIN;
-                       else
-                               retval = -ERESTARTSYS;
-                       break;
-               }
-               if (!(port->port.flags & ASYNC_CLOSING) &&
-                               (do_clocal ||
-                               (inb(port->ioaddr + UART_MSR) & UART_MSR_DCD)))
-                       break;
-               if (signal_pending(current)) {
-                       retval = -ERESTARTSYS;
-                       break;
-               }
-               schedule();
-       }
-       set_current_state(TASK_RUNNING);
-       remove_wait_queue(&port->port.open_wait, &wait);
-       if (!tty_hung_up_p(filp))
-               port->port.count++;
-       port->port.blocked_open--;
-       if (retval)
-               return retval;
-       port->port.flags |= ASYNC_NORMAL_ACTIVE;
-       return 0;
+       spin_lock_irqsave(&mp->slock, flags);
+       outb(inb(mp->ioaddr + UART_MCR) |
+               UART_MCR_DTR | UART_MCR_RTS, mp->ioaddr + UART_MCR);
+       spin_unlock_irqrestore(&mp->slock, flags);
 }
 
 static int mxser_set_baud(struct tty_struct *tty, long newspd)
@@ -1087,14 +1034,14 @@ static int mxser_open(struct tty_struct *tty, struct file *filp)
        /*
         * Start up serial port
         */
-       spin_lock_irqsave(&info->slock, flags);
+       spin_lock_irqsave(&info->port.lock, flags);
        info->port.count++;
-       spin_unlock_irqrestore(&info->slock, flags);
+       spin_unlock_irqrestore(&info->port.lock, flags);
        retval = mxser_startup(tty);
        if (retval)
                return retval;
 
-       retval = mxser_block_til_ready(tty, filp, info);
+       retval = tty_port_block_til_ready(&info->port, tty, filp);
        if (retval)
                return retval;
 
@@ -1133,57 +1080,26 @@ static void mxser_flush_buffer(struct tty_struct *tty)
 static void mxser_close(struct tty_struct *tty, struct file *filp)
 {
        struct mxser_port *info = tty->driver_data;
+       struct tty_port *port = &info->port;
 
        unsigned long timeout;
-       unsigned long flags;
 
        if (tty->index == MXSER_PORTS)
                return;
        if (!info)
                return;
 
-       spin_lock_irqsave(&info->slock, flags);
-
-       if (tty_hung_up_p(filp)) {
-               spin_unlock_irqrestore(&info->slock, flags);
-               return;
-       }
-       if ((tty->count == 1) && (info->port.count != 1)) {
-               /*
-                * Uh, oh.  tty->count is 1, which means that the tty
-                * structure will be freed.  Info->port.count should always
-                * be one in these conditions.  If it's greater than
-                * one, we've got real problems, since it means the
-                * serial port won't be shutdown.
-                */
-               printk(KERN_ERR "mxser_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 "mxser_close: bad serial port count for "
-                       "ttys%d: %d\n", tty->index, info->port.count);
-               info->port.count = 0;
-       }
-       if (info->port.count) {
-               spin_unlock_irqrestore(&info->slock, flags);
+       if (tty_port_close_start(port, tty, filp) == 0)
                return;
-       }
-       info->port.flags |= ASYNC_CLOSING;
-       spin_unlock_irqrestore(&info->slock, flags);
+
        /*
         * Save the termios structure, since this port may have
         * separate termios for callout and dialin.
+        *
+        * FIXME: Can this go ?
         */
        if (info->port.flags & ASYNC_NORMAL_ACTIVE)
                info->normal_termios = *tty->termios;
-       /*
-        * 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->port.closing_wait != ASYNC_CLOSING_WAIT_NONE)
-               tty_wait_until_sent(tty, info->port.closing_wait);
        /*
         * At this point we stop accepting input.  To do this, we
         * disable the receive line status interrupts, and tell the
@@ -1209,19 +1125,12 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
                }
        }
        mxser_shutdown(tty);
-
        mxser_flush_buffer(tty);
-       tty_ldisc_flush(tty);
-
-       tty->closing = 0;
-       tty_port_tty_set(&info->port, NULL);
-       if (info->port.blocked_open) {
-               if (info->port.close_delay)
-                       schedule_timeout_interruptible(info->port.close_delay);
-               wake_up_interruptible(&info->port.open_wait);
-       }
 
-       info->port.flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
+       /* Right now the tty_port set is done outside of the close_end helper
+          as we don't yet have everyone using refcounts */     
+       tty_port_close_end(port, tty);
+       tty_port_tty_set(port, NULL);
 }
 
 static int mxser_write(struct tty_struct *tty, const unsigned char *buf, int count)
@@ -2146,10 +2055,7 @@ static void mxser_hangup(struct tty_struct *tty)
 
        mxser_flush_buffer(tty);
        mxser_shutdown(tty);
-       info->port.count = 0;
-       info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
-       tty_port_tty_set(&info->port, NULL);
-       wake_up_interruptible(&info->port.open_wait);
+       tty_port_hangup(&info->port);
 }
 
 /*
@@ -2449,6 +2355,11 @@ static const struct tty_operations mxser_ops = {
        .tiocmset = mxser_tiocmset,
 };
 
+struct tty_port_operations mxser_port_ops = {
+       .carrier_raised = mxser_carrier_raised,
+       .raise_dtr_rts = mxser_raise_dtr_rts,
+};
+
 /*
  * The MOXA Smartio/Industio serial driver boot-time initialization code!
  */
@@ -2482,6 +2393,7 @@ static int __devinit mxser_initbrd(struct mxser_board *brd,
        for (i = 0; i < brd->info->nports; i++) {
                info = &brd->ports[i];
                tty_port_init(&info->port);
+               info->port.ops = &mxser_port_ops;
                info->board = brd;
                info->stop_rx = 0;
                info->ldisc_stop_rx = 0;
index 4a8215a89ad3fe4287b0f5f4560844b0c3cb4b2e..d2e93e34322696134bd622d4212649a7fc05d81b 100644 (file)
@@ -1003,7 +1003,7 @@ static int r3964_open(struct tty_struct *tty)
 
 static void r3964_close(struct tty_struct *tty)
 {
-       struct r3964_info *pInfo = (struct r3964_info *)tty->disc_data;
+       struct r3964_info *pInfo = tty->disc_data;
        struct r3964_client_info *pClient, *pNext;
        struct r3964_message *pMsg;
        struct r3964_block_header *pHeader, *pNextHeader;
@@ -1058,7 +1058,7 @@ static void r3964_close(struct tty_struct *tty)
 static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
                          unsigned char __user * buf, size_t nr)
 {
-       struct r3964_info *pInfo = (struct r3964_info *)tty->disc_data;
+       struct r3964_info *pInfo = tty->disc_data;
        struct r3964_client_info *pClient;
        struct r3964_message *pMsg;
        struct r3964_client_message theMsg;
@@ -1113,7 +1113,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
 static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
                           const unsigned char *data, size_t count)
 {
-       struct r3964_info *pInfo = (struct r3964_info *)tty->disc_data;
+       struct r3964_info *pInfo = tty->disc_data;
        struct r3964_block_header *pHeader;
        struct r3964_client_info *pClient;
        unsigned char *new_data;
@@ -1182,7 +1182,7 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
 static int r3964_ioctl(struct tty_struct *tty, struct file *file,
                unsigned int cmd, unsigned long arg)
 {
-       struct r3964_info *pInfo = (struct r3964_info *)tty->disc_data;
+       struct r3964_info *pInfo = tty->disc_data;
        if (pInfo == NULL)
                return -EINVAL;
        switch (cmd) {
@@ -1216,7 +1216,7 @@ static void r3964_set_termios(struct tty_struct *tty, struct ktermios *old)
 static unsigned int r3964_poll(struct tty_struct *tty, struct file *file,
                        struct poll_table_struct *wait)
 {
-       struct r3964_info *pInfo = (struct r3964_info *)tty->disc_data;
+       struct r3964_info *pInfo = tty->disc_data;
        struct r3964_client_info *pClient;
        struct r3964_message *pMsg = NULL;
        unsigned long flags;
@@ -1241,7 +1241,7 @@ static unsigned int r3964_poll(struct tty_struct *tty, struct file *file,
 static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,
                        char *fp, int count)
 {
-       struct r3964_info *pInfo = (struct r3964_info *)tty->disc_data;
+       struct r3964_info *pInfo = tty->disc_data;
        const unsigned char *p;
        char *f, flags = 0;
        int i;
index efbfe9612658bc5cd32b0e36c77e8651a3363746..f6f0e4ec2b510dde6ca5079f6def074e34f6fdce 100644 (file)
@@ -47,8 +47,8 @@
 #include <linux/bitops.h>
 #include <linux/audit.h>
 #include <linux/file.h>
+#include <linux/uaccess.h>
 
-#include <asm/uaccess.h>
 #include <asm/system.h>
 
 /* number of characters left in xmit buffer before select has we have room */
 #define TTY_THRESHOLD_THROTTLE         128 /* now based on remaining room */
 #define TTY_THRESHOLD_UNTHROTTLE       128
 
+/*
+ * Special byte codes used in the echo buffer to represent operations
+ * or special handling of characters.  Bytes in the echo buffer that
+ * are not part of such special blocks are treated as normal character
+ * codes.
+ */
+#define ECHO_OP_START 0xff
+#define ECHO_OP_MOVE_BACK_COL 0x80
+#define ECHO_OP_SET_CANON_COL 0x81
+#define ECHO_OP_ERASE_TAB 0x82
+
 static inline unsigned char *alloc_buf(void)
 {
        gfp_t prio = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
@@ -169,6 +180,7 @@ static void check_unthrottle(struct tty_struct *tty)
  *
  *     Locking: tty_read_lock for read fields.
  */
+
 static void reset_buffer_flags(struct tty_struct *tty)
 {
        unsigned long flags;
@@ -176,6 +188,11 @@ static void reset_buffer_flags(struct tty_struct *tty)
        spin_lock_irqsave(&tty->read_lock, flags);
        tty->read_head = tty->read_tail = tty->read_cnt = 0;
        spin_unlock_irqrestore(&tty->read_lock, flags);
+
+       mutex_lock(&tty->echo_lock);
+       tty->echo_pos = tty->echo_cnt = tty->echo_overrun = 0;
+       mutex_unlock(&tty->echo_lock);
+
        tty->canon_head = tty->canon_data = tty->erasing = 0;
        memset(&tty->read_flags, 0, sizeof tty->read_flags);
        n_tty_set_room(tty);
@@ -266,89 +283,118 @@ static inline int is_continuation(unsigned char c, struct tty_struct *tty)
 }
 
 /**
- *     opost                   -       output post processor
+ *     do_output_char                  -       output one character
  *     @c: character (or partial unicode symbol)
  *     @tty: terminal device
+ *     @space: space available in tty driver write buffer
  *
- *     Perform OPOST processing.  Returns -1 when the output device is
- *     full and the character must be retried. Note that Linux currently
- *     ignores TABDLY, CRDLY, VTDLY, FFDLY and NLDLY. They simply aren't
- *     relevant in the world today. If you ever need them, add them here.
+ *     This is a helper function that handles one output character
+ *     (including special characters like TAB, CR, LF, etc.),
+ *     putting the results in the tty driver's write buffer.
+ *
+ *     Note that Linux currently ignores TABDLY, CRDLY, VTDLY, FFDLY
+ *     and NLDLY.  They simply aren't relevant in the world today.
+ *     If you ever need them, add them here.
+ *
+ *     Returns the number of bytes of buffer space used or -1 if
+ *     no space left.
  *
- *     Called from both the receive and transmit sides and can be called
- *     re-entrantly. Relies on lock_kernel() for tty->column state.
+ *     Locking: should be called under the output_lock to protect
+ *              the column state and space left in the buffer
  */
 
-static int opost(unsigned char c, struct tty_struct *tty)
+static int do_output_char(unsigned char c, struct tty_struct *tty, int space)
 {
-       int     space, spaces;
+       int     spaces;
 
-       space = tty_write_room(tty);
        if (!space)
                return -1;
 
-       lock_kernel();
-       if (O_OPOST(tty)) {
-               switch (c) {
-               case '\n':
-                       if (O_ONLRET(tty))
-                               tty->column = 0;
-                       if (O_ONLCR(tty)) {
-                               if (space < 2) {
-                                       unlock_kernel();
-                                       return -1;
-                               }
-                               tty_put_char(tty, '\r');
-                               tty->column = 0;
-                       }
-                       tty->canon_column = tty->column;
-                       break;
-               case '\r':
-                       if (O_ONOCR(tty) && tty->column == 0) {
-                               unlock_kernel();
-                               return 0;
-                       }
-                       if (O_OCRNL(tty)) {
-                               c = '\n';
-                               if (O_ONLRET(tty))
-                                       tty->canon_column = tty->column = 0;
-                               break;
-                       }
+       switch (c) {
+       case '\n':
+               if (O_ONLRET(tty))
+                       tty->column = 0;
+               if (O_ONLCR(tty)) {
+                       if (space < 2)
+                               return -1;
                        tty->canon_column = tty->column = 0;
+                       tty_put_char(tty, '\r');
+                       tty_put_char(tty, c);
+                       return 2;
+               }
+               tty->canon_column = tty->column;
+               break;
+       case '\r':
+               if (O_ONOCR(tty) && tty->column == 0)
+                       return 0;
+               if (O_OCRNL(tty)) {
+                       c = '\n';
+                       if (O_ONLRET(tty))
+                               tty->canon_column = tty->column = 0;
                        break;
-               case '\t':
-                       spaces = 8 - (tty->column & 7);
-                       if (O_TABDLY(tty) == XTABS) {
-                               if (space < spaces) {
-                                       unlock_kernel();
-                                       return -1;
-                               }
-                               tty->column += spaces;
-                               tty->ops->write(tty, "        ", spaces);
-                               unlock_kernel();
-                               return 0;
-                       }
+               }
+               tty->canon_column = tty->column = 0;
+               break;
+       case '\t':
+               spaces = 8 - (tty->column & 7);
+               if (O_TABDLY(tty) == XTABS) {
+                       if (space < spaces)
+                               return -1;
                        tty->column += spaces;
-                       break;
-               case '\b':
-                       if (tty->column > 0)
-                               tty->column--;
-                       break;
-               default:
+                       tty->ops->write(tty, "        ", spaces);
+                       return spaces;
+               }
+               tty->column += spaces;
+               break;
+       case '\b':
+               if (tty->column > 0)
+                       tty->column--;
+               break;
+       default:
+               if (!iscntrl(c)) {
                        if (O_OLCUC(tty))
                                c = toupper(c);
-                       if (!iscntrl(c) && !is_continuation(c, tty))
+                       if (!is_continuation(c, tty))
                                tty->column++;
-                       break;
                }
+               break;
        }
+
        tty_put_char(tty, c);
-       unlock_kernel();
-       return 0;
+       return 1;
 }
 
 /**
- *     opost_block             -       block postprocess
+ *     process_output                  -       output post processor
+ *     @c: character (or partial unicode symbol)
+ *     @tty: terminal device
+ *
+ *     Perform OPOST processing.  Returns -1 when the output device is
+ *     full and the character must be retried.
+ *
+ *     Locking: output_lock to protect column state and space left
+ *              (also, this is called from n_tty_write under the
+ *               tty layer write lock)
+ */
+
+static int process_output(unsigned char c, struct tty_struct *tty)
+{
+       int     space, retval;
+
+       mutex_lock(&tty->output_lock);
+
+       space = tty_write_room(tty);
+       retval = do_output_char(c, tty, space);
+
+       mutex_unlock(&tty->output_lock);
+       if (retval < 0)
+               return -1;
+       else
+               return 0;
+}
+
+/**
+ *     process_output_block            -       block post processor
  *     @tty: terminal device
  *     @inbuf: user buffer
  *     @nr: number of bytes
@@ -358,26 +404,32 @@ static int opost(unsigned char c, struct tty_struct *tty)
  *     the simple cases normally found and helps to generate blocks of
  *     symbols for the console driver and thus improve performance.
  *
- *     Called from n_tty_write under the tty layer write lock. Relies
- *     on lock_kernel for the tty->column state.
+ *     Locking: output_lock to protect column state and space left
+ *              (also, this is called from n_tty_write under the
+ *               tty layer write lock)
  */
 
-static ssize_t opost_block(struct tty_struct *tty,
-                      const unsigned char *buf, unsigned int nr)
+static ssize_t process_output_block(struct tty_struct *tty,
+                                   const unsigned char *buf, unsigned int nr)
 {
        int     space;
        int     i;
        const unsigned char *cp;
 
+       mutex_lock(&tty->output_lock);
+
        space = tty_write_room(tty);
-       if (!space)
+       if (!space) {
+               mutex_unlock(&tty->output_lock);
                return 0;
+       }
        if (nr > space)
                nr = space;
 
-       lock_kernel();
        for (i = 0, cp = buf; i < nr; i++, cp++) {
-               switch (*cp) {
+               unsigned char c = *cp;
+
+               switch (c) {
                case '\n':
                        if (O_ONLRET(tty))
                                tty->column = 0;
@@ -399,54 +451,403 @@ static ssize_t opost_block(struct tty_struct *tty,
                                tty->column--;
                        break;
                default:
-                       if (O_OLCUC(tty))
-                               goto break_out;
-                       if (!iscntrl(*cp))
-                               tty->column++;
+                       if (!iscntrl(c)) {
+                               if (O_OLCUC(tty))
+                                       goto break_out;
+                               if (!is_continuation(c, tty))
+                                       tty->column++;
+                       }
                        break;
                }
        }
 break_out:
-       if (tty->ops->flush_chars)
-               tty->ops->flush_chars(tty);
        i = tty->ops->write(tty, buf, i);
-       unlock_kernel();
+
+       mutex_unlock(&tty->output_lock);
        return i;
 }
 
+/**
+ *     process_echoes  -       write pending echo characters
+ *     @tty: terminal device
+ *
+ *     Write previously buffered echo (and other ldisc-generated)
+ *     characters to the tty.
+ *
+ *     Characters generated by the ldisc (including echoes) need to
+ *     be buffered because the driver's write buffer can fill during
+ *     heavy program output.  Echoing straight to the driver will
+ *     often fail under these conditions, causing lost characters and
+ *     resulting mismatches of ldisc state information.
+ *
+ *     Since the ldisc state must represent the characters actually sent
+ *     to the driver at the time of the write, operations like certain
+ *     changes in column state are also saved in the buffer and executed
+ *     here.
+ *
+ *     A circular fifo buffer is used so that the most recent characters
+ *     are prioritized.  Also, when control characters are echoed with a
+ *     prefixed "^", the pair is treated atomically and thus not separated.
+ *
+ *     Locking: output_lock to protect column state and space left,
+ *              echo_lock to protect the echo buffer
+ */
+
+static void process_echoes(struct tty_struct *tty)
+{
+       int     space, nr;
+       unsigned char c;
+       unsigned char *cp, *buf_end;
+
+       if (!tty->echo_cnt)
+               return;
+
+       mutex_lock(&tty->output_lock);
+       mutex_lock(&tty->echo_lock);
+
+       space = tty_write_room(tty);
+
+       buf_end = tty->echo_buf + N_TTY_BUF_SIZE;
+       cp = tty->echo_buf + tty->echo_pos;
+       nr = tty->echo_cnt;
+       while (nr > 0) {
+               c = *cp;
+               if (c == ECHO_OP_START) {
+                       unsigned char op;
+                       unsigned char *opp;
+                       int no_space_left = 0;
+
+                       /*
+                        * If the buffer byte is the start of a multi-byte
+                        * operation, get the next byte, which is either the
+                        * op code or a control character value.
+                        */
+                       opp = cp + 1;
+                       if (opp == buf_end)
+                               opp -= N_TTY_BUF_SIZE;
+                       op = *opp;
+
+                       switch (op) {
+                               unsigned int num_chars, num_bs;
+
+                       case ECHO_OP_ERASE_TAB:
+                               if (++opp == buf_end)
+                                       opp -= N_TTY_BUF_SIZE;
+                               num_chars = *opp;
+
+                               /*
+                                * Determine how many columns to go back
+                                * in order to erase the tab.
+                                * This depends on the number of columns
+                                * used by other characters within the tab
+                                * area.  If this (modulo 8) count is from
+                                * the start of input rather than from a
+                                * previous tab, we offset by canon column.
+                                * Otherwise, tab spacing is normal.
+                                */
+                               if (!(num_chars & 0x80))
+                                       num_chars += tty->canon_column;
+                               num_bs = 8 - (num_chars & 7);
+
+                               if (num_bs > space) {
+                                       no_space_left = 1;
+                                       break;
+                               }
+                               space -= num_bs;
+                               while (num_bs--) {
+                                       tty_put_char(tty, '\b');
+                                       if (tty->column > 0)
+                                               tty->column--;
+                               }
+                               cp += 3;
+                               nr -= 3;
+                               break;
+
+                       case ECHO_OP_SET_CANON_COL:
+                               tty->canon_column = tty->column;
+                               cp += 2;
+                               nr -= 2;
+                               break;
+
+                       case ECHO_OP_MOVE_BACK_COL:
+                               if (tty->column > 0)
+                                       tty->column--;
+                               cp += 2;
+                               nr -= 2;
+                               break;
+
+                       case ECHO_OP_START:
+                               /* This is an escaped echo op start code */
+                               if (!space) {
+                                       no_space_left = 1;
+                                       break;
+                               }
+                               tty_put_char(tty, ECHO_OP_START);
+                               tty->column++;
+                               space--;
+                               cp += 2;
+                               nr -= 2;
+                               break;
+
+                       default:
+                               if (iscntrl(op)) {
+                                       if (L_ECHOCTL(tty)) {
+                                               /*
+                                                * Ensure there is enough space
+                                                * for the whole ctrl pair.
+                                                */
+                                               if (space < 2) {
+                                                       no_space_left = 1;
+                                                       break;
+                                               }
+                                               tty_put_char(tty, '^');
+                                               tty_put_char(tty, op ^ 0100);
+                                               tty->column += 2;
+                                               space -= 2;
+                                       } else {
+                                               if (!space) {
+                                                       no_space_left = 1;
+                                                       break;
+                                               }
+                                               tty_put_char(tty, op);
+                                               space--;
+                                       }
+                               }
+                               /*
+                                * If above falls through, this was an
+                                * undefined op.
+                                */
+                               cp += 2;
+                               nr -= 2;
+                       }
+
+                       if (no_space_left)
+                               break;
+               } else {
+                       int retval;
+
+                       retval = do_output_char(c, tty, space);
+                       if (retval < 0)
+                               break;
+                       space -= retval;
+                       cp += 1;
+                       nr -= 1;
+               }
+
+               /* When end of circular buffer reached, wrap around */
+               if (cp >= buf_end)
+                       cp -= N_TTY_BUF_SIZE;
+       }
+
+       if (nr == 0) {
+               tty->echo_pos = 0;
+               tty->echo_cnt = 0;
+               tty->echo_overrun = 0;
+       } else {
+               int num_processed = tty->echo_cnt - nr;
+               tty->echo_pos += num_processed;
+               tty->echo_pos &= N_TTY_BUF_SIZE - 1;
+               tty->echo_cnt = nr;
+               if (num_processed > 0)
+                       tty->echo_overrun = 0;
+       }
+
+       mutex_unlock(&tty->echo_lock);
+       mutex_unlock(&tty->output_lock);
+
+       if (tty->ops->flush_chars)
+               tty->ops->flush_chars(tty);
+}
 
 /**
- *     echo_char       -       echo characters
+ *     add_echo_byte   -       add a byte to the echo buffer
+ *     @c: unicode byte to echo
+ *     @tty: terminal device
+ *
+ *     Add a character or operation byte to the echo buffer.
+ *
+ *     Should be called under the echo lock to protect the echo buffer.
+ */
+
+static void add_echo_byte(unsigned char c, struct tty_struct *tty)
+{
+       int     new_byte_pos;
+
+       if (tty->echo_cnt == N_TTY_BUF_SIZE) {
+               /* Circular buffer is already at capacity */
+               new_byte_pos = tty->echo_pos;
+
+               /*
+                * Since the buffer start position needs to be advanced,
+                * be sure to step by a whole operation byte group.
+                */
+               if (tty->echo_buf[tty->echo_pos] == ECHO_OP_START) {
+                       if (tty->echo_buf[(tty->echo_pos + 1) &
+                                         (N_TTY_BUF_SIZE - 1)] ==
+                                               ECHO_OP_ERASE_TAB) {
+                               tty->echo_pos += 3;
+                               tty->echo_cnt -= 2;
+                       } else {
+                               tty->echo_pos += 2;
+                               tty->echo_cnt -= 1;
+                       }
+               } else {
+                       tty->echo_pos++;
+               }
+               tty->echo_pos &= N_TTY_BUF_SIZE - 1;
+
+               tty->echo_overrun = 1;
+       } else {
+               new_byte_pos = tty->echo_pos + tty->echo_cnt;
+               new_byte_pos &= N_TTY_BUF_SIZE - 1;
+               tty->echo_cnt++;
+       }
+
+       tty->echo_buf[new_byte_pos] = c;
+}
+
+/**
+ *     echo_move_back_col      -       add operation to move back a column
+ *     @tty: terminal device
+ *
+ *     Add an operation to the echo buffer to move back one column.
+ *
+ *     Locking: echo_lock to protect the echo buffer
+ */
+
+static void echo_move_back_col(struct tty_struct *tty)
+{
+       mutex_lock(&tty->echo_lock);
+
+       add_echo_byte(ECHO_OP_START, tty);
+       add_echo_byte(ECHO_OP_MOVE_BACK_COL, tty);
+
+       mutex_unlock(&tty->echo_lock);
+}
+
+/**
+ *     echo_set_canon_col      -       add operation to set the canon column
+ *     @tty: terminal device
+ *
+ *     Add an operation to the echo buffer to set the canon column
+ *     to the current column.
+ *
+ *     Locking: echo_lock to protect the echo buffer
+ */
+
+static void echo_set_canon_col(struct tty_struct *tty)
+{
+       mutex_lock(&tty->echo_lock);
+
+       add_echo_byte(ECHO_OP_START, tty);
+       add_echo_byte(ECHO_OP_SET_CANON_COL, tty);
+
+       mutex_unlock(&tty->echo_lock);
+}
+
+/**
+ *     echo_erase_tab  -       add operation to erase a tab
+ *     @num_chars: number of character columns already used
+ *     @after_tab: true if num_chars starts after a previous tab
+ *     @tty: terminal device
+ *
+ *     Add an operation to the echo buffer to erase a tab.
+ *
+ *     Called by the eraser function, which knows how many character
+ *     columns have been used since either a previous tab or the start
+ *     of input.  This information will be used later, along with
+ *     canon column (if applicable), to go back the correct number
+ *     of columns.
+ *
+ *     Locking: echo_lock to protect the echo buffer
+ */
+
+static void echo_erase_tab(unsigned int num_chars, int after_tab,
+                          struct tty_struct *tty)
+{
+       mutex_lock(&tty->echo_lock);
+
+       add_echo_byte(ECHO_OP_START, tty);
+       add_echo_byte(ECHO_OP_ERASE_TAB, tty);
+
+       /* We only need to know this modulo 8 (tab spacing) */
+       num_chars &= 7;
+
+       /* Set the high bit as a flag if num_chars is after a previous tab */
+       if (after_tab)
+               num_chars |= 0x80;
+
+       add_echo_byte(num_chars, tty);
+
+       mutex_unlock(&tty->echo_lock);
+}
+
+/**
+ *     echo_char_raw   -       echo a character raw
  *     @c: unicode byte to echo
  *     @tty: terminal device
  *
  *     Echo user input back onto the screen. This must be called only when
  *     L_ECHO(tty) is true. Called from the driver receive_buf path.
  *
- *     Relies on BKL for tty column locking
+ *     This variant does not treat control characters specially.
+ *
+ *     Locking: echo_lock to protect the echo buffer
+ */
+
+static void echo_char_raw(unsigned char c, struct tty_struct *tty)
+{
+       mutex_lock(&tty->echo_lock);
+
+       if (c == ECHO_OP_START) {
+               add_echo_byte(ECHO_OP_START, tty);
+               add_echo_byte(ECHO_OP_START, tty);
+       } else {
+               add_echo_byte(c, tty);
+       }
+
+       mutex_unlock(&tty->echo_lock);
+}
+
+/**
+ *     echo_char       -       echo a character
+ *     @c: unicode byte to echo
+ *     @tty: terminal device
+ *
+ *     Echo user input back onto the screen. This must be called only when
+ *     L_ECHO(tty) is true. Called from the driver receive_buf path.
+ *
+ *     This variant tags control characters to be possibly echoed as
+ *     as "^X" (where X is the letter representing the control char).
+ *
+ *     Locking: echo_lock to protect the echo buffer
  */
 
 static void echo_char(unsigned char c, struct tty_struct *tty)
 {
-       if (L_ECHOCTL(tty) && iscntrl(c) && c != '\t') {
-               tty_put_char(tty, '^');
-               tty_put_char(tty, c ^ 0100);
-               tty->column += 2;
-       } else
-               opost(c, tty);
+       mutex_lock(&tty->echo_lock);
+
+       if (c == ECHO_OP_START) {
+               add_echo_byte(ECHO_OP_START, tty);
+               add_echo_byte(ECHO_OP_START, tty);
+       } else {
+               if (iscntrl(c) && c != '\t')
+                       add_echo_byte(ECHO_OP_START, tty);
+               add_echo_byte(c, tty);
+       }
+
+       mutex_unlock(&tty->echo_lock);
 }
 
 /**
- *     finsh_erasing           -       complete erase
+ *     finish_erasing          -       complete erase
  *     @tty: tty doing the erase
- *
- *     Relies on BKL for tty column locking
  */
+
 static inline void finish_erasing(struct tty_struct *tty)
 {
        if (tty->erasing) {
-               tty_put_char(tty, '/');
-               tty->column++;
+               echo_char_raw('/', tty);
                tty->erasing = 0;
        }
 }
@@ -460,7 +861,7 @@ static inline void finish_erasing(struct tty_struct *tty)
  *     present in the stream from the driver layer. Handles the complexities
  *     of UTF-8 multibyte symbols.
  *
- *     Locking: read_lock for tty buffers, BKL for column/erasing state
+ *     Locking: read_lock for tty buffers
  */
 
 static void eraser(unsigned char c, struct tty_struct *tty)
@@ -471,7 +872,7 @@ static void eraser(unsigned char c, struct tty_struct *tty)
 
        /* FIXME: locking needed ? */
        if (tty->read_head == tty->canon_head) {
-               /* opost('\a', tty); */         /* what do you think? */
+               /* process_output('\a', tty); */ /* what do you think? */
                return;
        }
        if (c == ERASE_CHAR(tty))
@@ -497,7 +898,7 @@ static void eraser(unsigned char c, struct tty_struct *tty)
                        echo_char(KILL_CHAR(tty), tty);
                        /* Add a newline if ECHOK is on and ECHOKE is off. */
                        if (L_ECHOK(tty))
-                               opost('\n', tty);
+                               echo_char_raw('\n', tty);
                        return;
                }
                kill_type = KILL;
@@ -533,67 +934,61 @@ static void eraser(unsigned char c, struct tty_struct *tty)
                if (L_ECHO(tty)) {
                        if (L_ECHOPRT(tty)) {
                                if (!tty->erasing) {
-                                       tty_put_char(tty, '\\');
-                                       tty->column++;
+                                       echo_char_raw('\\', tty);
                                        tty->erasing = 1;
                                }
                                /* if cnt > 1, output a multi-byte character */
                                echo_char(c, tty);
                                while (--cnt > 0) {
                                        head = (head+1) & (N_TTY_BUF_SIZE-1);
-                                       tty_put_char(tty, tty->read_buf[head]);
+                                       echo_char_raw(tty->read_buf[head], tty);
+                                       echo_move_back_col(tty);
                                }
                        } else if (kill_type == ERASE && !L_ECHOE(tty)) {
                                echo_char(ERASE_CHAR(tty), tty);
                        } else if (c == '\t') {
-                               unsigned int col = tty->canon_column;
-                               unsigned long tail = tty->canon_head;
-
-                               /* Find the column of the last char. */
-                               while (tail != tty->read_head) {
+                               unsigned int num_chars = 0;
+                               int after_tab = 0;
+                               unsigned long tail = tty->read_head;
+
+                               /*
+                                * Count the columns used for characters
+                                * since the start of input or after a
+                                * previous tab.
+                                * This info is used to go back the correct
+                                * number of columns.
+                                */
+                               while (tail != tty->canon_head) {
+                                       tail = (tail-1) & (N_TTY_BUF_SIZE-1);
                                        c = tty->read_buf[tail];
-                                       if (c == '\t')
-                                               col = (col | 7) + 1;
-                                       else if (iscntrl(c)) {
+                                       if (c == '\t') {
+                                               after_tab = 1;
+                                               break;
+                                       } else if (iscntrl(c)) {
                                                if (L_ECHOCTL(tty))
-                                                       col += 2;
-                                       } else if (!is_continuation(c, tty))
-                                               col++;
-                                       tail = (tail+1) & (N_TTY_BUF_SIZE-1);
-                               }
-
-                               /* should never happen */
-                               if (tty->column > 0x80000000)
-                                       tty->column = 0;
-
-                               /* Now backup to that column. */
-                               while (tty->column > col) {
-                                       /* Can't use opost here. */
-                                       tty_put_char(tty, '\b');
-                                       if (tty->column > 0)
-                                               tty->column--;
+                                                       num_chars += 2;
+                                       } else if (!is_continuation(c, tty)) {
+                                               num_chars++;
+                                       }
                                }
+                               echo_erase_tab(num_chars, after_tab, tty);
                        } else {
                                if (iscntrl(c) && L_ECHOCTL(tty)) {
-                                       tty_put_char(tty, '\b');
-                                       tty_put_char(tty, ' ');
-                                       tty_put_char(tty, '\b');
-                                       if (tty->column > 0)
-                                               tty->column--;
+                                       echo_char_raw('\b', tty);
+                                       echo_char_raw(' ', tty);
+                                       echo_char_raw('\b', tty);
                                }
                                if (!iscntrl(c) || L_ECHOCTL(tty)) {
-                                       tty_put_char(tty, '\b');
-                                       tty_put_char(tty, ' ');
-                                       tty_put_char(tty, '\b');
-                                       if (tty->column > 0)
-                                               tty->column--;
+                                       echo_char_raw('\b', tty);
+                                       echo_char_raw(' ', tty);
+                                       echo_char_raw('\b', tty);
                                }
                        }
                }
                if (kill_type == ERASE)
                        break;
        }
-       if (tty->read_head == tty->canon_head)
+       if (tty->read_head == tty->canon_head && L_ECHO(tty))
                finish_erasing(tty);
 }
 
@@ -712,6 +1107,7 @@ static inline void n_tty_receive_parity_error(struct tty_struct *tty,
 static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
 {
        unsigned long flags;
+       int parmrk;
 
        if (tty->raw) {
                put_tty_queue(c, tty);
@@ -721,18 +1117,21 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
        if (I_ISTRIP(tty))
                c &= 0x7f;
        if (I_IUCLC(tty) && L_IEXTEN(tty))
-               c=tolower(c);
+               c = tolower(c);
 
        if (tty->stopped && !tty->flow_stopped && I_IXON(tty) &&
-           ((I_IXANY(tty) && c != START_CHAR(tty) && c != STOP_CHAR(tty)) ||
-            c == INTR_CHAR(tty) || c == QUIT_CHAR(tty) || c == SUSP_CHAR(tty)))
+           I_IXANY(tty) && c != START_CHAR(tty) && c != STOP_CHAR(tty) &&
+           c != INTR_CHAR(tty) && c != QUIT_CHAR(tty) && c != SUSP_CHAR(tty)) {
                start_tty(tty);
+               process_echoes(tty);
+       }
 
        if (tty->closing) {
                if (I_IXON(tty)) {
-                       if (c == START_CHAR(tty))
+                       if (c == START_CHAR(tty)) {
                                start_tty(tty);
-                       else if (c == STOP_CHAR(tty))
+                               process_echoes(tty);
+                       } else if (c == STOP_CHAR(tty))
                                stop_tty(tty);
                }
                return;
@@ -745,19 +1144,23 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
         * up.
         */
        if (!test_bit(c, tty->process_char_map) || tty->lnext) {
-               finish_erasing(tty);
                tty->lnext = 0;
+               parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0;
+               if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) {
+                       /* beep if no space */
+                       if (L_ECHO(tty))
+                               process_output('\a', tty);
+                       return;
+               }
                if (L_ECHO(tty)) {
-                       if (tty->read_cnt >= N_TTY_BUF_SIZE-1) {
-                               tty_put_char(tty, '\a'); /* beep if no space */
-                               return;
-                       }
+                       finish_erasing(tty);
                        /* Record the column of first canon char. */
                        if (tty->canon_head == tty->read_head)
-                               tty->canon_column = tty->column;
+                               echo_set_canon_col(tty);
                        echo_char(c, tty);
+                       process_echoes(tty);
                }
-               if (I_PARMRK(tty) && c == (unsigned char) '\377')
+               if (parmrk)
                        put_tty_queue(c, tty);
                put_tty_queue(c, tty);
                return;
@@ -766,6 +1169,7 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
        if (I_IXON(tty)) {
                if (c == START_CHAR(tty)) {
                        start_tty(tty);
+                       process_echoes(tty);
                        return;
                }
                if (c == STOP_CHAR(tty)) {
@@ -786,7 +1190,6 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
                if (c == SUSP_CHAR(tty)) {
 send_signal:
                        /*
-                        * Echo character, and then send the signal.
                         * Note that we do not use isig() here because we want
                         * the order to be:
                         * 1) flush, 2) echo, 3) signal
@@ -795,8 +1198,12 @@ send_signal:
                                n_tty_flush_buffer(tty);
                                tty_driver_flush_buffer(tty);
                        }
-                       if (L_ECHO(tty))
+                       if (I_IXON(tty))
+                               start_tty(tty);
+                       if (L_ECHO(tty)) {
                                echo_char(c, tty);
+                               process_echoes(tty);
+                       }
                        if (tty->pgrp)
                                kill_pgrp(tty->pgrp, signal, 1);
                        return;
@@ -815,6 +1222,7 @@ send_signal:
                if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) ||
                    (c == WERASE_CHAR(tty) && L_IEXTEN(tty))) {
                        eraser(c, tty);
+                       process_echoes(tty);
                        return;
                }
                if (c == LNEXT_CHAR(tty) && L_IEXTEN(tty)) {
@@ -822,8 +1230,9 @@ send_signal:
                        if (L_ECHO(tty)) {
                                finish_erasing(tty);
                                if (L_ECHOCTL(tty)) {
-                                       tty_put_char(tty, '^');
-                                       tty_put_char(tty, '\b');
+                                       echo_char_raw('^', tty);
+                                       echo_char_raw('\b', tty);
+                                       process_echoes(tty);
                                }
                        }
                        return;
@@ -834,22 +1243,29 @@ send_signal:
 
                        finish_erasing(tty);
                        echo_char(c, tty);
-                       opost('\n', tty);
+                       echo_char_raw('\n', tty);
                        while (tail != tty->read_head) {
                                echo_char(tty->read_buf[tail], tty);
                                tail = (tail+1) & (N_TTY_BUF_SIZE-1);
                        }
+                       process_echoes(tty);
                        return;
                }
                if (c == '\n') {
+                       if (tty->read_cnt >= N_TTY_BUF_SIZE) {
+                               if (L_ECHO(tty))
+                                       process_output('\a', tty);
+                               return;
+                       }
                        if (L_ECHO(tty) || L_ECHONL(tty)) {
-                               if (tty->read_cnt >= N_TTY_BUF_SIZE-1)
-                                       tty_put_char(tty, '\a');
-                               opost('\n', tty);
+                               echo_char_raw('\n', tty);
+                               process_echoes(tty);
                        }
                        goto handle_newline;
                }
                if (c == EOF_CHAR(tty)) {
+                       if (tty->read_cnt >= N_TTY_BUF_SIZE)
+                               return;
                        if (tty->canon_head != tty->read_head)
                                set_bit(TTY_PUSH, &tty->flags);
                        c = __DISABLED_CHAR;
@@ -857,22 +1273,28 @@ send_signal:
                }
                if ((c == EOL_CHAR(tty)) ||
                    (c == EOL2_CHAR(tty) && L_IEXTEN(tty))) {
+                       parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty))
+                                ? 1 : 0;
+                       if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk)) {
+                               if (L_ECHO(tty))
+                                       process_output('\a', tty);
+                               return;
+                       }
                        /*
                         * XXX are EOL_CHAR and EOL2_CHAR echoed?!?
                         */
                        if (L_ECHO(tty)) {
-                               if (tty->read_cnt >= N_TTY_BUF_SIZE-1)
-                                       tty_put_char(tty, '\a');
                                /* Record the column of first canon char. */
                                if (tty->canon_head == tty->read_head)
-                                       tty->canon_column = tty->column;
+                                       echo_set_canon_col(tty);
                                echo_char(c, tty);
+                               process_echoes(tty);
                        }
                        /*
                         * XXX does PARMRK doubling happen for
                         * EOL_CHAR and EOL2_CHAR?
                         */
-                       if (I_PARMRK(tty) && c == (unsigned char) '\377')
+                       if (parmrk)
                                put_tty_queue(c, tty);
 
 handle_newline:
@@ -889,23 +1311,27 @@ handle_newline:
                }
        }
 
-       finish_erasing(tty);
+       parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0;
+       if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) {
+               /* beep if no space */
+               if (L_ECHO(tty))
+                       process_output('\a', tty);
+               return;
+       }
        if (L_ECHO(tty)) {
-               if (tty->read_cnt >= N_TTY_BUF_SIZE-1) {
-                       tty_put_char(tty, '\a'); /* beep if no space */
-                       return;
-               }
+               finish_erasing(tty);
                if (c == '\n')
-                       opost('\n', tty);
+                       echo_char_raw('\n', tty);
                else {
                        /* Record the column of first canon char. */
                        if (tty->canon_head == tty->read_head)
-                               tty->canon_column = tty->column;
+                               echo_set_canon_col(tty);
                        echo_char(c, tty);
                }
+               process_echoes(tty);
        }
 
-       if (I_PARMRK(tty) && c == (unsigned char) '\377')
+       if (parmrk)
                put_tty_queue(c, tty);
 
        put_tty_queue(c, tty);
@@ -923,10 +1349,11 @@ handle_newline:
 
 static void n_tty_write_wakeup(struct tty_struct *tty)
 {
-       if (tty->fasync) {
-               set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+       /* Write out any echoed characters that are still pending */
+       process_echoes(tty);
+
+       if (tty->fasync && test_and_clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags))
                kill_fasync(&tty->fasync, SIGIO, POLL_OUT);
-       }
 }
 
 /**
@@ -1134,6 +1561,10 @@ static void n_tty_close(struct tty_struct *tty)
                free_buf(tty->read_buf);
                tty->read_buf = NULL;
        }
+       if (tty->echo_buf) {
+               free_buf(tty->echo_buf);
+               tty->echo_buf = NULL;
+       }
 }
 
 /**
@@ -1151,13 +1582,19 @@ static int n_tty_open(struct tty_struct *tty)
        if (!tty)
                return -EINVAL;
 
-       /* This one is ugly. Currently a malloc failure here can panic */
+       /* These are ugly. Currently a malloc failure here can panic */
        if (!tty->read_buf) {
                tty->read_buf = alloc_buf();
                if (!tty->read_buf)
                        return -ENOMEM;
        }
+       if (!tty->echo_buf) {
+               tty->echo_buf = alloc_buf();
+               if (!tty->echo_buf)
+                       return -ENOMEM;
+       }
        memset(tty->read_buf, 0, N_TTY_BUF_SIZE);
+       memset(tty->echo_buf, 0, N_TTY_BUF_SIZE);
        reset_buffer_flags(tty);
        tty->column = 0;
        n_tty_set_termios(tty, NULL);
@@ -1487,16 +1924,23 @@ do_it_again:
  *     @buf: userspace buffer pointer
  *     @nr: size of I/O
  *
- *     Write function of the terminal device. This is serialized with
+ *     Write function of the terminal device.  This is serialized with
  *     respect to other write callers but not to termios changes, reads
- *     and other such events. We must be careful with N_TTY as the receive
- *     code will echo characters, thus calling driver write methods.
+ *     and other such events.  Since the receive code will echo characters,
+ *     thus calling driver write methods, the output_lock is used in
+ *     the output processing functions called here as well as in the
+ *     echo processing function to protect the column state and space
+ *     left in the buffer.
  *
  *     This code must be sure never to sleep through a hangup.
+ *
+ *     Locking: output_lock to protect column state and space left
+ *              (note that the process_output*() functions take this
+ *               lock themselves)
  */
 
 static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
-                         const unsigned char *buf, size_t nr)
+                          const unsigned char *buf, size_t nr)
 {
        const unsigned char *b = buf;
        DECLARE_WAITQUEUE(wait, current);
@@ -1510,6 +1954,9 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
                        return retval;
        }
 
+       /* Write out any echoed characters that are still pending */
+       process_echoes(tty);
+
        add_wait_queue(&tty->write_wait, &wait);
        while (1) {
                set_current_state(TASK_INTERRUPTIBLE);
@@ -1523,7 +1970,7 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
                }
                if (O_OPOST(tty) && !(test_bit(TTY_HW_COOK_OUT, &tty->flags))) {
                        while (nr > 0) {
-                               ssize_t num = opost_block(tty, b, nr);
+                               ssize_t num = process_output_block(tty, b, nr);
                                if (num < 0) {
                                        if (num == -EAGAIN)
                                                break;
@@ -1535,7 +1982,7 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
                                if (nr == 0)
                                        break;
                                c = *b;
-                               if (opost(c, tty) < 0)
+                               if (process_output(c, tty) < 0)
                                        break;
                                b++; nr--;
                        }
@@ -1565,6 +2012,8 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
 break_out:
        __set_current_state(TASK_RUNNING);
        remove_wait_queue(&tty->write_wait, &wait);
+       if (b - buf != nr && tty->fasync)
+               set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
        return (b - buf) ? b - buf : retval;
 }
 
@@ -1663,4 +2112,3 @@ struct tty_ldisc_ops tty_ldisc_N_TTY = {
        .receive_buf     = n_tty_receive_buf,
        .write_wakeup    = n_tty_write_wakeup
 };
-
index 9a34a1935283370a837bd0c72fa5d05463ff2ae7..d6102b644b550d0f9a306b015dd985f642d7e974 100644 (file)
@@ -353,6 +353,7 @@ struct ctrl_ul {
 
 /* This holds all information that is needed regarding a port */
 struct port {
+       struct tty_port port;
        u8 update_flow_control;
        struct ctrl_ul ctrl_ul;
        struct ctrl_dl ctrl_dl;
@@ -365,8 +366,6 @@ struct port {
        u8 toggle_ul;
        u16 token_dl;
 
-       struct tty_struct *tty;
-       int tty_open_count;
        /* mutex to ensure one access patch to this port */
        struct mutex tty_sem;
        wait_queue_head_t tty_wait;
@@ -788,14 +787,14 @@ static void disable_transmit_dl(enum port_type port, struct nozomi *dc)
  * Return 1 - send buffer to card and ack.
  * Return 0 - don't ack, don't send buffer to card.
  */
-static int send_data(enum port_type index, const struct nozomi *dc)
+static int send_data(enum port_type index, struct nozomi *dc)
 {
        u32 size = 0;
-       const struct port *port = &dc->port[index];
+       struct port *port = &dc->port[index];
        const u8 toggle = port->toggle_ul;
        void __iomem *addr = port->ul_addr[toggle];
        const u32 ul_size = port->ul_size[toggle];
-       struct tty_struct *tty = port->tty;
+       struct tty_struct *tty = tty_port_tty_get(&port->port);
 
        /* Get data from tty and place in buf for now */
        size = __kfifo_get(port->fifo_ul, dc->send_buf,
@@ -803,6 +802,7 @@ static int send_data(enum port_type index, const struct nozomi *dc)
 
        if (size == 0) {
                DBG4("No more data to send, disable link:");
+               tty_kref_put(tty);
                return 0;
        }
 
@@ -815,6 +815,7 @@ static int send_data(enum port_type index, const struct nozomi *dc)
        if (tty)
                tty_wakeup(tty);
 
+       tty_kref_put(tty);
        return 1;
 }
 
@@ -826,7 +827,7 @@ static int receive_data(enum port_type index, struct nozomi *dc)
        u32 offset = 4;
        struct port *port = &dc->port[index];
        void __iomem *addr = port->dl_addr[port->toggle_dl];
-       struct tty_struct *tty = port->tty;
+       struct tty_struct *tty = tty_port_tty_get(&port->port);
        int i;
 
        if (unlikely(!tty)) {
@@ -870,7 +871,7 @@ static int receive_data(enum port_type index, struct nozomi *dc)
        }
 
        set_bit(index, &dc->flip);
-
+       tty_kref_put(tty);
        return 1;
 }
 
@@ -1276,9 +1277,15 @@ static irqreturn_t interrupt_handler(int irq, void *dev_id)
 
 exit_handler:
        spin_unlock(&dc->spin_mutex);
-       for (a = 0; a < NOZOMI_MAX_PORTS; a++)
-               if (test_and_clear_bit(a, &dc->flip))
-                       tty_flip_buffer_push(dc->port[a].tty);
+       for (a = 0; a < NOZOMI_MAX_PORTS; a++) {
+               struct tty_struct *tty;
+               if (test_and_clear_bit(a, &dc->flip)) {
+                       tty = tty_port_tty_get(&dc->port[a].port);
+                       if (tty)
+                               tty_flip_buffer_push(tty);
+                       tty_kref_put(tty);
+               }
+       }
        return IRQ_HANDLED;
 none:
        spin_unlock(&dc->spin_mutex);
@@ -1453,12 +1460,10 @@ static int __devinit nozomi_card_init(struct pci_dev *pdev,
 
        for (i = 0; i < MAX_PORT; i++) {
                mutex_init(&dc->port[i].tty_sem);
-               dc->port[i].tty_open_count = 0;
-               dc->port[i].tty = NULL;
+               tty_port_init(&dc->port[i].port);
                tty_register_device(ntty_driver, dc->index_start + i,
                                                        &pdev->dev);
        }
-
        return 0;
 
 err_free_sbuf:
@@ -1482,14 +1487,16 @@ static void __devexit tty_exit(struct nozomi *dc)
 
        flush_scheduled_work();
 
-       for (i = 0; i < MAX_PORT; ++i)
-               if (dc->port[i].tty && \
-                               list_empty(&dc->port[i].tty->hangup_work.entry))
-                       tty_hangup(dc->port[i].tty);
-
+       for (i = 0; i < MAX_PORT; ++i) {
+               struct tty_struct *tty = tty_port_tty_get(&dc->port[i].port);
+               if (tty && list_empty(&tty->hangup_work.entry))
+                       tty_hangup(tty);
+               tty_kref_put(tty);
+       }
+       /* Racy below - surely should wait for scheduled work to be done or
+          complete off a hangup method ? */
        while (dc->open_ttys)
                msleep(1);
-
        for (i = dc->index_start; i < dc->index_start + MAX_PORT; ++i)
                tty_unregister_device(ntty_driver, i);
 }
@@ -1579,23 +1586,22 @@ static int ntty_open(struct tty_struct *tty, struct file *file)
        if (mutex_lock_interruptible(&port->tty_sem))
                return -ERESTARTSYS;
 
-       port->tty_open_count++;
+       port->port.count++;
        dc->open_ttys++;
 
        /* Enable interrupt downlink for channel */
-       if (port->tty_open_count == 1) {
+       if (port->port.count == 1) {
+               /* FIXME: is this needed now ? */
                tty->low_latency = 1;
                tty->driver_data = port;
-               port->tty = tty;
+               tty_port_tty_set(&port->port, tty);
                DBG1("open: %d", port->token_dl);
                spin_lock_irqsave(&dc->spin_mutex, flags);
                dc->last_ier = dc->last_ier | port->token_dl;
                writew(dc->last_ier, dc->reg_ier);
                spin_unlock_irqrestore(&dc->spin_mutex, flags);
        }
-
        mutex_unlock(&port->tty_sem);
-
        return 0;
 }
 
@@ -1606,31 +1612,30 @@ static int ntty_open(struct tty_struct *tty, struct file *file)
 static void ntty_close(struct tty_struct *tty, struct file *file)
 {
        struct nozomi *dc = get_dc_by_tty(tty);
-       struct port *port = tty->driver_data;
+       struct port *nport = tty->driver_data;
+       struct tty_port *port = &nport->port;
        unsigned long flags;
 
-       if (!dc || !port)
+       if (!dc || !nport)
                return;
 
-       if (mutex_lock_interruptible(&port->tty_sem))
-               return;
+       /* Users cannot interrupt a close */
+       mutex_lock(&nport->tty_sem);
 
-       if (!port->tty_open_count)
-               goto exit;
+       WARN_ON(!port->count);
 
        dc->open_ttys--;
-       port->tty_open_count--;
+       port->count--;
+       tty_port_tty_set(port, NULL);
 
-       if (port->tty_open_count == 0) {
-               DBG1("close: %d", port->token_dl);
+       if (port->count == 0) {
+               DBG1("close: %d", nport->token_dl);
                spin_lock_irqsave(&dc->spin_mutex, flags);
-               dc->last_ier &= ~(port->token_dl);
+               dc->last_ier &= ~(nport->token_dl);
                writew(dc->last_ier, dc->reg_ier);
                spin_unlock_irqrestore(&dc->spin_mutex, flags);
        }
-
-exit:
-       mutex_unlock(&port->tty_sem);
+       mutex_unlock(&nport->tty_sem);
 }
 
 /*
@@ -1660,7 +1665,7 @@ static int ntty_write(struct tty_struct *tty, const unsigned char *buffer,
                return -EAGAIN;
        }
 
-       if (unlikely(!port->tty_open_count)) {
+       if (unlikely(!port->port.count)) {
                DBG1(" ");
                goto exit;
        }
@@ -1710,7 +1715,7 @@ static int ntty_write_room(struct tty_struct *tty)
        if (!mutex_trylock(&port->tty_sem))
                return 0;
 
-       if (!port->tty_open_count)
+       if (!port->port.count)
                goto exit;
 
        room = port->fifo_ul->size - __kfifo_len(port->fifo_ul);
@@ -1866,7 +1871,7 @@ static s32 ntty_chars_in_buffer(struct tty_struct *tty)
                goto exit_in_buffer;
        }
 
-       if (unlikely(!port->tty_open_count)) {
+       if (unlikely(!port->port.count)) {
                dev_err(&dc->pdev->dev, "No tty open?\n");
                rval = -ENODEV;
                goto exit_in_buffer;
index 4d64a02612a42f96e07450afac5ce4e900de3f6c..dc073e167abc68ed14f3dc67332568a845aac429 100644 (file)
@@ -138,20 +138,15 @@ struct _input_signal_events {
  */
 
 typedef struct _mgslpc_info {
+       struct tty_port         port;
        void *if_ptr;   /* General purpose pointer (used by SPPP) */
        int                     magic;
-       int                     flags;
-       int                     count;          /* count of opens */
        int                     line;
-       unsigned short          close_delay;
-       unsigned short          closing_wait;   /* time to wait before closing */
 
        struct mgsl_icount      icount;
 
-       struct tty_struct       *tty;
        int                     timeout;
        int                     x_char;         /* xon/xoff character */
-       int                     blocked_open;   /* # of blocked opens */
        unsigned char           read_status_mask;
        unsigned char           ignore_status_mask;
 
@@ -170,9 +165,6 @@ typedef struct _mgslpc_info {
        int            rx_buf_count;   /* total number of rx buffers */
        int            rx_frame_count; /* number of full rx buffers */
 
-       wait_queue_head_t       open_wait;
-       wait_queue_head_t       close_wait;
-
        wait_queue_head_t       status_event_wait_q;
        wait_queue_head_t       event_wait_q;
        struct timer_list       tx_timer;       /* HDLC transmit timeout timer */
@@ -375,7 +367,7 @@ static void irq_enable(MGSLPC_INFO *info, unsigned char channel, unsigned short
 static void rx_start(MGSLPC_INFO *info);
 static void rx_stop(MGSLPC_INFO *info);
 
-static void tx_start(MGSLPC_INFO *info);
+static void tx_start(MGSLPC_INFO *info, struct tty_struct *tty);
 static void tx_stop(MGSLPC_INFO *info);
 static void tx_set_idle(MGSLPC_INFO *info);
 
@@ -389,7 +381,8 @@ static void async_mode(MGSLPC_INFO *info);
 
 static void tx_timeout(unsigned long context);
 
-static int ioctl_common(MGSLPC_INFO *info, unsigned int cmd, unsigned long arg);
+static int carrier_raised(struct tty_port *port);
+static void raise_dtr_rts(struct tty_port *port);
 
 #if SYNCLINK_GENERIC_HDLC
 #define dev_to_port(D) (dev_to_hdlc(D)->priv)
@@ -410,7 +403,7 @@ static void release_resources(MGSLPC_INFO *info);
 static void mgslpc_add_device(MGSLPC_INFO *info);
 static void mgslpc_remove_device(MGSLPC_INFO *info);
 
-static bool rx_get_frame(MGSLPC_INFO *info);
+static bool rx_get_frame(MGSLPC_INFO *info, struct tty_struct *tty);
 static void rx_reset_buffers(MGSLPC_INFO *info);
 static int  rx_alloc_buffers(MGSLPC_INFO *info);
 static void rx_free_buffers(MGSLPC_INFO *info);
@@ -421,7 +414,7 @@ static irqreturn_t mgslpc_isr(int irq, void *dev_id);
  * Bottom half interrupt handlers
  */
 static void bh_handler(struct work_struct *work);
-static void bh_transmit(MGSLPC_INFO *info);
+static void bh_transmit(MGSLPC_INFO *info, struct tty_struct *tty);
 static void bh_status(MGSLPC_INFO *info);
 
 /*
@@ -432,10 +425,10 @@ static int tiocmset(struct tty_struct *tty, struct file *file,
                    unsigned int set, unsigned int clear);
 static int get_stats(MGSLPC_INFO *info, struct mgsl_icount __user *user_icount);
 static int get_params(MGSLPC_INFO *info, MGSL_PARAMS __user *user_params);
-static int set_params(MGSLPC_INFO *info, MGSL_PARAMS __user *new_params);
+static int set_params(MGSLPC_INFO *info, MGSL_PARAMS __user *new_params, struct tty_struct *tty);
 static int get_txidle(MGSLPC_INFO *info, int __user *idle_mode);
 static int set_txidle(MGSLPC_INFO *info, int idle_mode);
-static int set_txenable(MGSLPC_INFO *info, int enable);
+static int set_txenable(MGSLPC_INFO *info, int enable, struct tty_struct *tty);
 static int tx_abort(MGSLPC_INFO *info);
 static int set_rxenable(MGSLPC_INFO *info, int enable);
 static int wait_events(MGSLPC_INFO *info, int __user *mask);
@@ -474,7 +467,7 @@ static struct tty_driver *serial_driver;
 /* number of characters left in xmit buffer before we ask for more */
 #define WAKEUP_CHARS 256
 
-static void mgslpc_change_params(MGSLPC_INFO *info);
+static void mgslpc_change_params(MGSLPC_INFO *info, struct tty_struct *tty);
 static void mgslpc_wait_until_sent(struct tty_struct *tty, int timeout);
 
 /* PCMCIA prototypes */
@@ -517,6 +510,11 @@ static void ldisc_receive_buf(struct tty_struct *tty,
        }
 }
 
+static const struct tty_port_operations mgslpc_port_ops = {
+       .carrier_raised = carrier_raised,
+       .raise_dtr_rts = raise_dtr_rts
+};
+
 static int mgslpc_probe(struct pcmcia_device *link)
 {
     MGSLPC_INFO *info;
@@ -532,12 +530,12 @@ static int mgslpc_probe(struct pcmcia_device *link)
     }
 
     info->magic = MGSLPC_MAGIC;
+    tty_port_init(&info->port);
+    info->port.ops = &mgslpc_port_ops;
     INIT_WORK(&info->task, bh_handler);
     info->max_frame_size = 4096;
-    info->close_delay = 5*HZ/10;
-    info->closing_wait = 30*HZ;
-    init_waitqueue_head(&info->open_wait);
-    init_waitqueue_head(&info->close_wait);
+    info->port.close_delay = 5*HZ/10;
+    info->port.closing_wait = 30*HZ;
     init_waitqueue_head(&info->status_event_wait_q);
     init_waitqueue_head(&info->event_wait_q);
     spin_lock_init(&info->lock);
@@ -784,7 +782,7 @@ static void tx_release(struct tty_struct *tty)
 
        spin_lock_irqsave(&info->lock,flags);
        if (!info->tx_enabled)
-               tx_start(info);
+               tx_start(info, tty);
        spin_unlock_irqrestore(&info->lock,flags);
 }
 
@@ -823,6 +821,7 @@ static int bh_action(MGSLPC_INFO *info)
 static void bh_handler(struct work_struct *work)
 {
        MGSLPC_INFO *info = container_of(work, MGSLPC_INFO, task);
+       struct tty_struct *tty;
        int action;
 
        if (!info)
@@ -833,6 +832,7 @@ static void bh_handler(struct work_struct *work)
                        __FILE__,__LINE__,info->device_name);
 
        info->bh_running = true;
+       tty = tty_port_tty_get(&info->port);
 
        while((action = bh_action(info)) != 0) {
 
@@ -844,10 +844,10 @@ static void bh_handler(struct work_struct *work)
                switch (action) {
 
                case BH_RECEIVE:
-                       while(rx_get_frame(info));
+                       while(rx_get_frame(info, tty));
                        break;
                case BH_TRANSMIT:
-                       bh_transmit(info);
+                       bh_transmit(info, tty);
                        break;
                case BH_STATUS:
                        bh_status(info);
@@ -859,14 +859,14 @@ static void bh_handler(struct work_struct *work)
                }
        }
 
+       tty_kref_put(tty);
        if (debug_level >= DEBUG_LEVEL_BH)
                printk( "%s(%d):bh_handler(%s) exit\n",
                        __FILE__,__LINE__,info->device_name);
 }
 
-static void bh_transmit(MGSLPC_INFO *info)
+static void bh_transmit(MGSLPC_INFO *info, struct tty_struct *tty)
 {
-       struct tty_struct *tty = info->tty;
        if (debug_level >= DEBUG_LEVEL_BH)
                printk("bh_transmit() entry on %s\n", info->device_name);
 
@@ -945,12 +945,11 @@ static void rx_ready_hdlc(MGSLPC_INFO *info, int eom)
        issue_command(info, CHA, CMD_RXFIFO);
 }
 
-static void rx_ready_async(MGSLPC_INFO *info, int tcd)
+static void rx_ready_async(MGSLPC_INFO *info, int tcd, struct tty_struct *tty)
 {
        unsigned char data, status, flag;
        int fifo_count;
        int work = 0;
-       struct tty_struct *tty = info->tty;
        struct mgsl_icount *icount = &info->icount;
 
        if (tcd) {
@@ -1013,7 +1012,7 @@ static void rx_ready_async(MGSLPC_INFO *info, int tcd)
 }
 
 
-static void tx_done(MGSLPC_INFO *info)
+static void tx_done(MGSLPC_INFO *info, struct tty_struct *tty)
 {
        if (!info->tx_active)
                return;
@@ -1042,7 +1041,7 @@ static void tx_done(MGSLPC_INFO *info)
        else
 #endif
        {
-               if (info->tty->stopped || info->tty->hw_stopped) {
+               if (tty->stopped || tty->hw_stopped) {
                        tx_stop(info);
                        return;
                }
@@ -1050,7 +1049,7 @@ static void tx_done(MGSLPC_INFO *info)
        }
 }
 
-static void tx_ready(MGSLPC_INFO *info)
+static void tx_ready(MGSLPC_INFO *info, struct tty_struct *tty)
 {
        unsigned char fifo_count = 32;
        int c;
@@ -1062,7 +1061,7 @@ static void tx_ready(MGSLPC_INFO *info)
                if (!info->tx_active)
                        return;
        } else {
-               if (info->tty->stopped || info->tty->hw_stopped) {
+               if (tty->stopped || tty->hw_stopped) {
                        tx_stop(info);
                        return;
                }
@@ -1099,7 +1098,7 @@ static void tx_ready(MGSLPC_INFO *info)
        }
 }
 
-static void cts_change(MGSLPC_INFO *info)
+static void cts_change(MGSLPC_INFO *info, struct tty_struct *tty)
 {
        get_signals(info);
        if ((info->cts_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT)
@@ -1112,14 +1111,14 @@ static void cts_change(MGSLPC_INFO *info)
        wake_up_interruptible(&info->status_event_wait_q);
        wake_up_interruptible(&info->event_wait_q);
 
-       if (info->flags & ASYNC_CTS_FLOW) {
-               if (info->tty->hw_stopped) {
+       if (info->port.flags & ASYNC_CTS_FLOW) {
+               if (tty->hw_stopped) {
                        if (info->serial_signals & SerialSignal_CTS) {
                                if (debug_level >= DEBUG_LEVEL_ISR)
                                        printk("CTS tx start...");
-                               if (info->tty)
-                                       info->tty->hw_stopped = 0;
-                               tx_start(info);
+                               if (tty)
+                                       tty->hw_stopped = 0;
+                               tx_start(info, tty);
                                info->pending_bh |= BH_TRANSMIT;
                                return;
                        }
@@ -1127,8 +1126,8 @@ static void cts_change(MGSLPC_INFO *info)
                        if (!(info->serial_signals & SerialSignal_CTS)) {
                                if (debug_level >= DEBUG_LEVEL_ISR)
                                        printk("CTS tx stop...");
-                               if (info->tty)
-                                       info->tty->hw_stopped = 1;
+                               if (tty)
+                                       tty->hw_stopped = 1;
                                tx_stop(info);
                        }
                }
@@ -1136,7 +1135,7 @@ static void cts_change(MGSLPC_INFO *info)
        info->pending_bh |= BH_STATUS;
 }
 
-static void dcd_change(MGSLPC_INFO *info)
+static void dcd_change(MGSLPC_INFO *info, struct tty_struct *tty)
 {
        get_signals(info);
        if ((info->dcd_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT)
@@ -1158,17 +1157,17 @@ static void dcd_change(MGSLPC_INFO *info)
        wake_up_interruptible(&info->status_event_wait_q);
        wake_up_interruptible(&info->event_wait_q);
 
-       if (info->flags & ASYNC_CHECK_CD) {
+       if (info->port.flags & ASYNC_CHECK_CD) {
                if (debug_level >= DEBUG_LEVEL_ISR)
                        printk("%s CD now %s...", info->device_name,
                               (info->serial_signals & SerialSignal_DCD) ? "on" : "off");
                if (info->serial_signals & SerialSignal_DCD)
-                       wake_up_interruptible(&info->open_wait);
+                       wake_up_interruptible(&info->port.open_wait);
                else {
                        if (debug_level >= DEBUG_LEVEL_ISR)
                                printk("doing serial hangup...");
-                       if (info->tty)
-                               tty_hangup(info->tty);
+                       if (tty)
+                               tty_hangup(tty);
                }
        }
        info->pending_bh |= BH_STATUS;
@@ -1214,6 +1213,7 @@ static void ri_change(MGSLPC_INFO *info)
 static irqreturn_t mgslpc_isr(int dummy, void *dev_id)
 {
        MGSLPC_INFO *info = dev_id;
+       struct tty_struct *tty;
        unsigned short isr;
        unsigned char gis, pis;
        int count=0;
@@ -1224,6 +1224,8 @@ static irqreturn_t mgslpc_isr(int dummy, void *dev_id)
        if (!(info->p_dev->_locked))
                return IRQ_HANDLED;
 
+       tty = tty_port_tty_get(&info->port);
+
        spin_lock(&info->lock);
 
        while ((gis = read_reg(info, CHA + GIS))) {
@@ -1239,9 +1241,9 @@ static irqreturn_t mgslpc_isr(int dummy, void *dev_id)
                if (gis & (BIT1 + BIT0)) {
                        isr = read_reg16(info, CHB + ISR);
                        if (isr & IRQ_DCD)
-                               dcd_change(info);
+                               dcd_change(info, tty);
                        if (isr & IRQ_CTS)
-                               cts_change(info);
+                               cts_change(info, tty);
                }
                if (gis & (BIT3 + BIT2))
                {
@@ -1258,8 +1260,8 @@ static irqreturn_t mgslpc_isr(int dummy, void *dev_id)
                        }
                        if (isr & IRQ_BREAK_ON) {
                                info->icount.brk++;
-                               if (info->flags & ASYNC_SAK)
-                                       do_SAK(info->tty);
+                               if (info->port.flags & ASYNC_SAK)
+                                       do_SAK(tty);
                        }
                        if (isr & IRQ_RXTIME) {
                                issue_command(info, CHA, CMD_RXFIFO_READ);
@@ -1268,7 +1270,7 @@ static irqreturn_t mgslpc_isr(int dummy, void *dev_id)
                                if (info->params.mode == MGSL_MODE_HDLC)
                                        rx_ready_hdlc(info, isr & IRQ_RXEOM);
                                else
-                                       rx_ready_async(info, isr & IRQ_RXEOM);
+                                       rx_ready_async(info, isr & IRQ_RXEOM, tty);
                        }
 
                        /* transmit IRQs */
@@ -1277,14 +1279,14 @@ static irqreturn_t mgslpc_isr(int dummy, void *dev_id)
                                        info->icount.txabort++;
                                else
                                        info->icount.txunder++;
-                               tx_done(info);
+                               tx_done(info, tty);
                        }
                        else if (isr & IRQ_ALLSENT) {
                                info->icount.txok++;
-                               tx_done(info);
+                               tx_done(info, tty);
                        }
                        else if (isr & IRQ_TXFIFO)
-                               tx_ready(info);
+                               tx_ready(info, tty);
                }
                if (gis & BIT7) {
                        pis = read_reg(info, CHA + PIS);
@@ -1308,6 +1310,7 @@ static irqreturn_t mgslpc_isr(int dummy, void *dev_id)
        }
 
        spin_unlock(&info->lock);
+       tty_kref_put(tty);
 
        if (debug_level >= DEBUG_LEVEL_ISR)
                printk("%s(%d):mgslpc_isr(%d)exit.\n",
@@ -1318,14 +1321,14 @@ static irqreturn_t mgslpc_isr(int dummy, void *dev_id)
 
 /* Initialize and start device.
  */
-static int startup(MGSLPC_INFO * info)
+static int startup(MGSLPC_INFO * info, struct tty_struct *tty)
 {
        int retval = 0;
 
        if (debug_level >= DEBUG_LEVEL_INFO)
                printk("%s(%d):startup(%s)\n",__FILE__,__LINE__,info->device_name);
 
-       if (info->flags & ASYNC_INITIALIZED)
+       if (info->port.flags & ASYNC_INITIALIZED)
                return 0;
 
        if (!info->tx_buf) {
@@ -1352,30 +1355,30 @@ static int startup(MGSLPC_INFO * info)
                retval = adapter_test(info);
 
        if ( retval ) {
-               if (capable(CAP_SYS_ADMIN) && info->tty)
-                       set_bit(TTY_IO_ERROR, &info->tty->flags);
+               if (capable(CAP_SYS_ADMIN) && tty)
+                       set_bit(TTY_IO_ERROR, &tty->flags);
                release_resources(info);
                return retval;
        }
 
        /* program hardware for current parameters */
-       mgslpc_change_params(info);
+       mgslpc_change_params(info, tty);
 
-       if (info->tty)
-               clear_bit(TTY_IO_ERROR, &info->tty->flags);
+       if (tty)
+               clear_bit(TTY_IO_ERROR, &tty->flags);
 
-       info->flags |= ASYNC_INITIALIZED;
+       info->port.flags |= ASYNC_INITIALIZED;
 
        return 0;
 }
 
 /* Called by mgslpc_close() and mgslpc_hangup() to shutdown hardware
  */
-static void shutdown(MGSLPC_INFO * info)
+static void shutdown(MGSLPC_INFO * info, struct tty_struct *tty)
 {
        unsigned long flags;
 
-       if (!(info->flags & ASYNC_INITIALIZED))
+       if (!(info->port.flags & ASYNC_INITIALIZED))
                return;
 
        if (debug_level >= DEBUG_LEVEL_INFO)
@@ -1402,7 +1405,7 @@ static void shutdown(MGSLPC_INFO * info)
        /* TODO:disable interrupts instead of reset to preserve signal states */
        reset_device(info);
 
-       if (!info->tty || info->tty->termios->c_cflag & HUPCL) {
+       if (!tty || tty->termios->c_cflag & HUPCL) {
                info->serial_signals &= ~(SerialSignal_DTR + SerialSignal_RTS);
                set_signals(info);
        }
@@ -1411,13 +1414,13 @@ static void shutdown(MGSLPC_INFO * info)
 
        release_resources(info);
 
-       if (info->tty)
-               set_bit(TTY_IO_ERROR, &info->tty->flags);
+       if (tty)
+               set_bit(TTY_IO_ERROR, &tty->flags);
 
-       info->flags &= ~ASYNC_INITIALIZED;
+       info->port.flags &= ~ASYNC_INITIALIZED;
 }
 
-static void mgslpc_program_hw(MGSLPC_INFO *info)
+static void mgslpc_program_hw(MGSLPC_INFO *info, struct tty_struct *tty)
 {
        unsigned long flags;
 
@@ -1443,7 +1446,7 @@ static void mgslpc_program_hw(MGSLPC_INFO *info)
        port_irq_enable(info, (unsigned char) PVR_DSR | PVR_RI);
        get_signals(info);
 
-       if (info->netcount || info->tty->termios->c_cflag & CREAD)
+       if (info->netcount || (tty && (tty->termios->c_cflag & CREAD)))
                rx_start(info);
 
        spin_unlock_irqrestore(&info->lock,flags);
@@ -1451,19 +1454,19 @@ static void mgslpc_program_hw(MGSLPC_INFO *info)
 
 /* Reconfigure adapter based on new parameters
  */
-static void mgslpc_change_params(MGSLPC_INFO *info)
+static void mgslpc_change_params(MGSLPC_INFO *info, struct tty_struct *tty)
 {
        unsigned cflag;
        int bits_per_char;
 
-       if (!info->tty || !info->tty->termios)
+       if (!tty || !tty->termios)
                return;
 
        if (debug_level >= DEBUG_LEVEL_INFO)
                printk("%s(%d):mgslpc_change_params(%s)\n",
                         __FILE__,__LINE__, info->device_name );
 
-       cflag = info->tty->termios->c_cflag;
+       cflag = tty->termios->c_cflag;
 
        /* if B0 rate (hangup) specified then negate DTR and RTS */
        /* otherwise assert DTR and RTS */
@@ -1510,7 +1513,7 @@ static void mgslpc_change_params(MGSLPC_INFO *info)
         * current data rate.
         */
        if (info->params.data_rate <= 460800) {
-               info->params.data_rate = tty_get_baud_rate(info->tty);
+               info->params.data_rate = tty_get_baud_rate(tty);
        }
 
        if ( info->params.data_rate ) {
@@ -1520,24 +1523,24 @@ static void mgslpc_change_params(MGSLPC_INFO *info)
        info->timeout += HZ/50;         /* Add .02 seconds of slop */
 
        if (cflag & CRTSCTS)
-               info->flags |= ASYNC_CTS_FLOW;
+               info->port.flags |= ASYNC_CTS_FLOW;
        else
-               info->flags &= ~ASYNC_CTS_FLOW;
+               info->port.flags &= ~ASYNC_CTS_FLOW;
 
        if (cflag & CLOCAL)
-               info->flags &= ~ASYNC_CHECK_CD;
+               info->port.flags &= ~ASYNC_CHECK_CD;
        else
-               info->flags |= ASYNC_CHECK_CD;
+               info->port.flags |= ASYNC_CHECK_CD;
 
        /* process tty input control flags */
 
        info->read_status_mask = 0;
-       if (I_INPCK(info->tty))
+       if (I_INPCK(tty))
                info->read_status_mask |= BIT7 | BIT6;
-       if (I_IGNPAR(info->tty))
+       if (I_IGNPAR(tty))
                info->ignore_status_mask |= BIT7 | BIT6;
 
-       mgslpc_program_hw(info);
+       mgslpc_program_hw(info, tty);
 }
 
 /* Add a character to the transmit buffer
@@ -1597,7 +1600,7 @@ static void mgslpc_flush_chars(struct tty_struct *tty)
 
        spin_lock_irqsave(&info->lock,flags);
        if (!info->tx_active)
-               tx_start(info);
+               tx_start(info, tty);
        spin_unlock_irqrestore(&info->lock,flags);
 }
 
@@ -1659,7 +1662,7 @@ start:
        if (info->tx_count && !tty->stopped && !tty->hw_stopped) {
                spin_lock_irqsave(&info->lock,flags);
                if (!info->tx_active)
-                       tx_start(info);
+                       tx_start(info, tty);
                spin_unlock_irqrestore(&info->lock,flags);
        }
 cleanup:
@@ -1764,7 +1767,7 @@ static void mgslpc_send_xchar(struct tty_struct *tty, char ch)
        if (ch) {
                spin_lock_irqsave(&info->lock,flags);
                if (!info->tx_enabled)
-                       tx_start(info);
+                       tx_start(info, tty);
                spin_unlock_irqrestore(&info->lock,flags);
        }
 }
@@ -1862,7 +1865,7 @@ static int get_params(MGSLPC_INFO * info, MGSL_PARAMS __user *user_params)
  *
  * Returns:    0 if success, otherwise error code
  */
-static int set_params(MGSLPC_INFO * info, MGSL_PARAMS __user *new_params)
+static int set_params(MGSLPC_INFO * info, MGSL_PARAMS __user *new_params, struct tty_struct *tty)
 {
        unsigned long flags;
        MGSL_PARAMS tmp_params;
@@ -1883,7 +1886,7 @@ static int set_params(MGSLPC_INFO * info, MGSL_PARAMS __user *new_params)
        memcpy(&info->params,&tmp_params,sizeof(MGSL_PARAMS));
        spin_unlock_irqrestore(&info->lock,flags);
 
-       mgslpc_change_params(info);
+       mgslpc_change_params(info, tty);
 
        return 0;
 }
@@ -1944,7 +1947,7 @@ static int set_interface(MGSLPC_INFO * info, int if_mode)
        return 0;
 }
 
-static int set_txenable(MGSLPC_INFO * info, int enable)
+static int set_txenable(MGSLPC_INFO * info, int enable, struct tty_struct *tty)
 {
        unsigned long flags;
 
@@ -1954,7 +1957,7 @@ static int set_txenable(MGSLPC_INFO * info, int enable)
        spin_lock_irqsave(&info->lock,flags);
        if (enable) {
                if (!info->tx_enabled)
-                       tx_start(info);
+                       tx_start(info, tty);
        } else {
                if (info->tx_enabled)
                        tx_stop(info);
@@ -2263,6 +2266,11 @@ static int mgslpc_ioctl(struct tty_struct *tty, struct file * file,
                        unsigned int cmd, unsigned long arg)
 {
        MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data;
+       int error;
+       struct mgsl_icount cnow;        /* kernel counter temps */
+       struct serial_icounter_struct __user *p_cuser;  /* user space */
+       void __user *argp = (void __user *)arg;
+       unsigned long flags;
 
        if (debug_level >= DEBUG_LEVEL_INFO)
                printk("%s(%d):mgslpc_ioctl %s cmd=%08X\n", __FILE__,__LINE__,
@@ -2277,22 +2285,11 @@ static int mgslpc_ioctl(struct tty_struct *tty, struct file * file,
                    return -EIO;
        }
 
-       return ioctl_common(info, cmd, arg);
-}
-
-static int ioctl_common(MGSLPC_INFO *info, unsigned int cmd, unsigned long arg)
-{
-       int error;
-       struct mgsl_icount cnow;        /* kernel counter temps */
-       struct serial_icounter_struct __user *p_cuser;  /* user space */
-       void __user *argp = (void __user *)arg;
-       unsigned long flags;
-
        switch (cmd) {
        case MGSL_IOCGPARAMS:
                return get_params(info, argp);
        case MGSL_IOCSPARAMS:
-               return set_params(info, argp);
+               return set_params(info, argp, tty);
        case MGSL_IOCGTXIDLE:
                return get_txidle(info, argp);
        case MGSL_IOCSTXIDLE:
@@ -2302,7 +2299,7 @@ static int ioctl_common(MGSLPC_INFO *info, unsigned int cmd, unsigned long arg)
        case MGSL_IOCSIF:
                return set_interface(info,(int)arg);
        case MGSL_IOCTXENABLE:
-               return set_txenable(info,(int)arg);
+               return set_txenable(info,(int)arg, tty);
        case MGSL_IOCRXENABLE:
                return set_rxenable(info,(int)arg);
        case MGSL_IOCTXABORT:
@@ -2369,7 +2366,7 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term
                == RELEVANT_IFLAG(old_termios->c_iflag)))
          return;
 
-       mgslpc_change_params(info);
+       mgslpc_change_params(info, tty);
 
        /* Handle transition to B0 status */
        if (old_termios->c_cflag & CBAUD &&
@@ -2404,81 +2401,34 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term
 static void mgslpc_close(struct tty_struct *tty, struct file * filp)
 {
        MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data;
+       struct tty_port *port = &info->port;
 
        if (mgslpc_paranoia_check(info, tty->name, "mgslpc_close"))
                return;
 
        if (debug_level >= DEBUG_LEVEL_INFO)
                printk("%s(%d):mgslpc_close(%s) entry, count=%d\n",
-                        __FILE__,__LINE__, info->device_name, info->count);
-
-       if (!info->count)
-               return;
+                        __FILE__,__LINE__, info->device_name, port->count);
 
-       if (tty_hung_up_p(filp))
-               goto cleanup;
-
-       if ((tty->count == 1) && (info->count != 1)) {
-               /*
-                * tty->count is 1 and the tty structure will be freed.
-                * info->count should be one in this case.
-                * if it's not, correct it so that the port is shutdown.
-                */
-               printk("mgslpc_close: bad refcount; tty->count is 1, "
-                      "info->count is %d\n", info->count);
-               info->count = 1;
-       }
+       WARN_ON(!port->count);
 
-       info->count--;
-
-       /* if at least one open remaining, leave hardware active */
-       if (info->count)
+       if (tty_port_close_start(port, tty, filp) == 0)
                goto cleanup;
 
-       info->flags |= ASYNC_CLOSING;
-
-       /* set tty->closing to notify line discipline to
-        * only process XON/XOFF characters. Only the N_TTY
-        * discipline appears to use this (ppp does not).
-        */
-       tty->closing = 1;
-
-       /* wait for transmit data to clear all layers */
-
-       if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) {
-               if (debug_level >= DEBUG_LEVEL_INFO)
-                       printk("%s(%d):mgslpc_close(%s) calling tty_wait_until_sent\n",
-                                __FILE__,__LINE__, info->device_name );
-               tty_wait_until_sent(tty, info->closing_wait);
-       }
-
-       if (info->flags & ASYNC_INITIALIZED)
+       if (port->flags & ASYNC_INITIALIZED)
                mgslpc_wait_until_sent(tty, info->timeout);
 
        mgslpc_flush_buffer(tty);
 
        tty_ldisc_flush(tty);
-
-       shutdown(info);
-
-       tty->closing = 0;
-       info->tty = NULL;
-
-       if (info->blocked_open) {
-               if (info->close_delay) {
-                       msleep_interruptible(jiffies_to_msecs(info->close_delay));
-               }
-               wake_up_interruptible(&info->open_wait);
-       }
-
-       info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
-
-       wake_up_interruptible(&info->close_wait);
-
+       shutdown(info, tty);
+       
+       tty_port_close_end(port, tty);
+       tty_port_tty_set(port, NULL);
 cleanup:
        if (debug_level >= DEBUG_LEVEL_INFO)
                printk("%s(%d):mgslpc_close(%s) exit, count=%d\n", __FILE__,__LINE__,
-                       tty->driver->name, info->count);
+                       tty->driver->name, port->count);
 }
 
 /* Wait until the transmitter is empty.
@@ -2498,7 +2448,7 @@ static void mgslpc_wait_until_sent(struct tty_struct *tty, int timeout)
        if (mgslpc_paranoia_check(info, tty->name, "mgslpc_wait_until_sent"))
                return;
 
-       if (!(info->flags & ASYNC_INITIALIZED))
+       if (!(info->port.flags & ASYNC_INITIALIZED))
                goto exit;
 
        orig_jiffies = jiffies;
@@ -2559,120 +2509,40 @@ static void mgslpc_hangup(struct tty_struct *tty)
                return;
 
        mgslpc_flush_buffer(tty);
-       shutdown(info);
-
-       info->count = 0;
-       info->flags &= ~ASYNC_NORMAL_ACTIVE;
-       info->tty = NULL;
-
-       wake_up_interruptible(&info->open_wait);
+       shutdown(info, tty);
+       tty_port_hangup(&info->port);
 }
 
-/* Block the current process until the specified port
- * is ready to be opened.
- */
-static int block_til_ready(struct tty_struct *tty, struct file *filp,
-                          MGSLPC_INFO *info)
+static int carrier_raised(struct tty_port *port)
 {
-       DECLARE_WAITQUEUE(wait, current);
-       int             retval;
-       bool            do_clocal = false;
-       bool            extra_count = false;
-       unsigned long   flags;
-
-       if (debug_level >= DEBUG_LEVEL_INFO)
-               printk("%s(%d):block_til_ready on %s\n",
-                        __FILE__,__LINE__, tty->driver->name );
-
-       if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){
-               /* nonblock mode is set or port is not enabled */
-               /* just verify that callout device is not active */
-               info->flags |= ASYNC_NORMAL_ACTIVE;
-               return 0;
-       }
-
-       if (tty->termios->c_cflag & CLOCAL)
-               do_clocal = true;
-
-       /* Wait for carrier detect and the line to become
-        * free (i.e., not in use by the callout).  While we are in
-        * this loop, info->count is dropped by one, so that
-        * mgslpc_close() knows when to free things.  We restore it upon
-        * exit, either normal or abnormal.
-        */
-
-       retval = 0;
-       add_wait_queue(&info->open_wait, &wait);
-
-       if (debug_level >= DEBUG_LEVEL_INFO)
-               printk("%s(%d):block_til_ready before block on %s count=%d\n",
-                        __FILE__,__LINE__, tty->driver->name, info->count );
-
-       spin_lock_irqsave(&info->lock, flags);
-       if (!tty_hung_up_p(filp)) {
-               extra_count = true;
-               info->count--;
-       }
-       spin_unlock_irqrestore(&info->lock, flags);
-       info->blocked_open++;
-
-       while (1) {
-               if ((tty->termios->c_cflag & CBAUD)) {
-                       spin_lock_irqsave(&info->lock,flags);
-                       info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
-                       set_signals(info);
-                       spin_unlock_irqrestore(&info->lock,flags);
-               }
-
-               set_current_state(TASK_INTERRUPTIBLE);
-
-               if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)){
-                       retval = (info->flags & ASYNC_HUP_NOTIFY) ?
-                                       -EAGAIN : -ERESTARTSYS;
-                       break;
-               }
-
-               spin_lock_irqsave(&info->lock,flags);
-               get_signals(info);
-               spin_unlock_irqrestore(&info->lock,flags);
-
-               if (!(info->flags & ASYNC_CLOSING) &&
-                   (do_clocal || (info->serial_signals & SerialSignal_DCD)) ) {
-                       break;
-               }
-
-               if (signal_pending(current)) {
-                       retval = -ERESTARTSYS;
-                       break;
-               }
-
-               if (debug_level >= DEBUG_LEVEL_INFO)
-                       printk("%s(%d):block_til_ready blocking on %s count=%d\n",
-                                __FILE__,__LINE__, tty->driver->name, info->count );
-
-               schedule();
-       }
-
-       set_current_state(TASK_RUNNING);
-       remove_wait_queue(&info->open_wait, &wait);
+       MGSLPC_INFO *info = container_of(port, MGSLPC_INFO, port);
+       unsigned long flags;
 
-       if (extra_count)
-               info->count++;
-       info->blocked_open--;
+       spin_lock_irqsave(&info->lock,flags);
+       get_signals(info);
+       spin_unlock_irqrestore(&info->lock,flags);
 
-       if (debug_level >= DEBUG_LEVEL_INFO)
-               printk("%s(%d):block_til_ready after blocking on %s count=%d\n",
-                        __FILE__,__LINE__, tty->driver->name, info->count );
+       if (info->serial_signals & SerialSignal_DCD)
+               return 1;
+       return 0;
+}
 
-       if (!retval)
-               info->flags |= ASYNC_NORMAL_ACTIVE;
+static void raise_dtr_rts(struct tty_port *port)
+{
+       MGSLPC_INFO *info = container_of(port, MGSLPC_INFO, port);
+       unsigned long flags;
 
-       return retval;
+       spin_lock_irqsave(&info->lock,flags);
+       info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
+       set_signals(info);
+       spin_unlock_irqrestore(&info->lock,flags);
 }
 
+
 static int mgslpc_open(struct tty_struct *tty, struct file * filp)
 {
        MGSLPC_INFO     *info;
+       struct tty_port *port;
        int                     retval, line;
        unsigned long flags;
 
@@ -2691,23 +2561,24 @@ static int mgslpc_open(struct tty_struct *tty, struct file * filp)
        if (mgslpc_paranoia_check(info, tty->name, "mgslpc_open"))
                return -ENODEV;
 
+       port = &info->port;
        tty->driver_data = info;
-       info->tty = tty;
+       tty_port_tty_set(port, tty);
 
        if (debug_level >= DEBUG_LEVEL_INFO)
                printk("%s(%d):mgslpc_open(%s), old ref count = %d\n",
-                        __FILE__,__LINE__,tty->driver->name, info->count);
+                        __FILE__,__LINE__,tty->driver->name, port->count);
 
        /* If port is closing, signal caller to try again */
-       if (tty_hung_up_p(filp) || info->flags & ASYNC_CLOSING){
-               if (info->flags & ASYNC_CLOSING)
-                       interruptible_sleep_on(&info->close_wait);
-               retval = ((info->flags & ASYNC_HUP_NOTIFY) ?
+       if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING){
+               if (port->flags & ASYNC_CLOSING)
+                       interruptible_sleep_on(&port->close_wait);
+               retval = ((port->flags & ASYNC_HUP_NOTIFY) ?
                        -EAGAIN : -ERESTARTSYS);
                goto cleanup;
        }
 
-       info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+       tty->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
 
        spin_lock_irqsave(&info->netlock, flags);
        if (info->netcount) {
@@ -2715,17 +2586,19 @@ static int mgslpc_open(struct tty_struct *tty, struct file * filp)
                spin_unlock_irqrestore(&info->netlock, flags);
                goto cleanup;
        }
-       info->count++;
+       spin_lock(&port->lock);
+       port->count++;
+       spin_unlock(&port->lock);
        spin_unlock_irqrestore(&info->netlock, flags);
 
-       if (info->count == 1) {
+       if (port->count == 1) {
                /* 1st open on this device, init hardware */
-               retval = startup(info);
+               retval = startup(info, tty);
                if (retval < 0)
                        goto cleanup;
        }
 
-       retval = block_til_ready(tty, filp, info);
+       retval = tty_port_block_til_ready(&info->port, tty, filp);
        if (retval) {
                if (debug_level >= DEBUG_LEVEL_INFO)
                        printk("%s(%d):block_til_ready(%s) returned %d\n",
@@ -2739,13 +2612,6 @@ static int mgslpc_open(struct tty_struct *tty, struct file * filp)
        retval = 0;
 
 cleanup:
-       if (retval) {
-               if (tty->count == 1)
-                       info->tty = NULL; /* tty layer will release tty struct */
-               if(info->count)
-                       info->count--;
-       }
-
        return retval;
 }
 
@@ -3500,7 +3366,7 @@ static void rx_start(MGSLPC_INFO *info)
        info->rx_enabled = true;
 }
 
-static void tx_start(MGSLPC_INFO *info)
+static void tx_start(MGSLPC_INFO *info, struct tty_struct *tty)
 {
        if (debug_level >= DEBUG_LEVEL_ISR)
                printk("%s(%d):tx_start(%s)\n",
@@ -3524,11 +3390,11 @@ static void tx_start(MGSLPC_INFO *info)
                if (info->params.mode == MGSL_MODE_ASYNC) {
                        if (!info->tx_active) {
                                info->tx_active = true;
-                               tx_ready(info);
+                               tx_ready(info, tty);
                        }
                } else {
                        info->tx_active = true;
-                       tx_ready(info);
+                       tx_ready(info, tty);
                        mod_timer(&info->tx_timer, jiffies +
                                        msecs_to_jiffies(5000));
                }
@@ -3849,13 +3715,12 @@ static void rx_reset_buffers(MGSLPC_INFO *info)
  *
  * Returns true if frame returned, otherwise false
  */
-static bool rx_get_frame(MGSLPC_INFO *info)
+static bool rx_get_frame(MGSLPC_INFO *info, struct tty_struct *tty)
 {
        unsigned short status;
        RXBUF *buf;
        unsigned int framesize = 0;
        unsigned long flags;
-       struct tty_struct *tty = info->tty;
        bool return_frame = false;
 
        if (info->rx_frame_count == 0)
@@ -4075,7 +3940,11 @@ static void tx_timeout(unsigned long context)
                hdlcdev_tx_done(info);
        else
 #endif
-               bh_transmit(info);
+       {
+               struct tty_struct *tty = tty_port_tty_get(&info->port);
+               bh_transmit(info, tty);
+               tty_kref_put(tty);
+       }
 }
 
 #if SYNCLINK_GENERIC_HDLC
@@ -4094,11 +3963,12 @@ static int hdlcdev_attach(struct net_device *dev, unsigned short encoding,
                          unsigned short parity)
 {
        MGSLPC_INFO *info = dev_to_port(dev);
+       struct tty_struct *tty;
        unsigned char  new_encoding;
        unsigned short new_crctype;
 
        /* return error if TTY interface open */
-       if (info->count)
+       if (info->port.count)
                return -EBUSY;
 
        switch (encoding)
@@ -4123,8 +3993,11 @@ static int hdlcdev_attach(struct net_device *dev, unsigned short encoding,
        info->params.crc_type = new_crctype;
 
        /* if network interface up, reprogram hardware */
-       if (info->netcount)
-               mgslpc_program_hw(info);
+       if (info->netcount) {
+               tty = tty_port_tty_get(&info->port);
+               mgslpc_program_hw(info, tty);
+               tty_kref_put(tty);
+       }
 
        return 0;
 }
@@ -4165,8 +4038,11 @@ static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev)
 
        /* start hardware transmitter if necessary */
        spin_lock_irqsave(&info->lock,flags);
-       if (!info->tx_active)
-               tx_start(info);
+       if (!info->tx_active) {
+               struct tty_struct *tty = tty_port_tty_get(&info->port);
+               tx_start(info, tty);
+               tty_kref_put(tty);
+       }
        spin_unlock_irqrestore(&info->lock,flags);
 
        return 0;
@@ -4183,6 +4059,7 @@ static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev)
 static int hdlcdev_open(struct net_device *dev)
 {
        MGSLPC_INFO *info = dev_to_port(dev);
+       struct tty_struct *tty;
        int rc;
        unsigned long flags;
 
@@ -4195,7 +4072,7 @@ static int hdlcdev_open(struct net_device *dev)
 
        /* arbitrate between network and tty opens */
        spin_lock_irqsave(&info->netlock, flags);
-       if (info->count != 0 || info->netcount != 0) {
+       if (info->port.count != 0 || info->netcount != 0) {
                printk(KERN_WARNING "%s: hdlc_open returning busy\n", dev->name);
                spin_unlock_irqrestore(&info->netlock, flags);
                return -EBUSY;
@@ -4203,17 +4080,19 @@ static int hdlcdev_open(struct net_device *dev)
        info->netcount=1;
        spin_unlock_irqrestore(&info->netlock, flags);
 
+       tty = tty_port_tty_get(&info->port);
        /* claim resources and init adapter */
-       if ((rc = startup(info)) != 0) {
+       if ((rc = startup(info, tty)) != 0) {
+               tty_kref_put(tty);
                spin_lock_irqsave(&info->netlock, flags);
                info->netcount=0;
                spin_unlock_irqrestore(&info->netlock, flags);
                return rc;
        }
-
        /* assert DTR and RTS, apply hardware settings */
        info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
-       mgslpc_program_hw(info);
+       mgslpc_program_hw(info, tty);
+       tty_kref_put(tty);
 
        /* enable network layer transmit */
        dev->trans_start = jiffies;
@@ -4241,6 +4120,7 @@ static int hdlcdev_open(struct net_device *dev)
 static int hdlcdev_close(struct net_device *dev)
 {
        MGSLPC_INFO *info = dev_to_port(dev);
+       struct tty_struct *tty = tty_port_tty_get(&info->port);
        unsigned long flags;
 
        if (debug_level >= DEBUG_LEVEL_INFO)
@@ -4249,8 +4129,8 @@ static int hdlcdev_close(struct net_device *dev)
        netif_stop_queue(dev);
 
        /* shutdown adapter and release resources */
-       shutdown(info);
-
+       shutdown(info, tty);
+       tty_kref_put(tty);
        hdlc_close(dev);
 
        spin_lock_irqsave(&info->netlock, flags);
@@ -4281,7 +4161,7 @@ static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                printk("%s:hdlcdev_ioctl(%s)\n",__FILE__,dev->name);
 
        /* return error if TTY interface open */
-       if (info->count)
+       if (info->port.count)
                return -EBUSY;
 
        if (cmd != SIOCWANDEV)
@@ -4354,8 +4234,11 @@ static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                        info->params.clock_speed = 0;
 
                /* if network interface up, reprogram hardware */
-               if (info->netcount)
-                       mgslpc_program_hw(info);
+               if (info->netcount) {
+                       struct tty_struct *tty = tty_port_tty_get(&info->port);
+                       mgslpc_program_hw(info, tty);
+                       tty_kref_put(tty);
+               }
                return 0;
 
        default:
index 6d4582712b1fa6ae1a1c40fbb792a3f863681657..112a6ba9a96fef2b3fec186bbaddce9944df752f 100644 (file)
@@ -5,8 +5,6 @@
  *
  *  Added support for a Unix98-style ptmx device.
  *    -- C. Scott Ananian <cananian@alumni.princeton.edu>, 14-Jan-1998
- *  Added TTY_DO_WRITE_WAKEUP to enable n_tty to send POLL_OUT to
- *      waiting writers -- Sapan Bhatia <sapan@corewars.org>
  *
  *  When reading this code see also fs/devpts. In particular note that the
  *  driver_data field is used by the devpts side as a binding to the devpts
@@ -217,7 +215,6 @@ static int pty_open(struct tty_struct *tty, struct file *filp)
 
        clear_bit(TTY_OTHER_CLOSED, &tty->link->flags);
        set_bit(TTY_THROTTLED, &tty->flags);
-       set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
        retval = 0;
 out:
        return retval;
@@ -230,6 +227,55 @@ static void pty_set_termios(struct tty_struct *tty,
        tty->termios->c_cflag |= (CS8 | CREAD);
 }
 
+/**
+ *     pty_do_resize           -       resize event
+ *     @tty: tty being resized
+ *     @real_tty: real tty (not the same as tty if using a pty/tty pair)
+ *     @rows: rows (character)
+ *     @cols: cols (character)
+ *
+ *     Update the termios variables and send the neccessary signals to
+ *     peform a terminal resize correctly
+ */
+
+int pty_resize(struct tty_struct *tty,  struct winsize *ws)
+{
+       struct pid *pgrp, *rpgrp;
+       unsigned long flags;
+       struct tty_struct *pty = tty->link;
+
+       /* For a PTY we need to lock the tty side */
+       mutex_lock(&tty->termios_mutex);
+       if (!memcmp(ws, &tty->winsize, sizeof(*ws)))
+               goto done;
+
+       /* Get the PID values and reference them so we can
+          avoid holding the tty ctrl lock while sending signals.
+          We need to lock these individually however. */
+
+       spin_lock_irqsave(&tty->ctrl_lock, flags);
+       pgrp = get_pid(tty->pgrp);
+       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+
+       spin_lock_irqsave(&pty->ctrl_lock, flags);
+       rpgrp = get_pid(pty->pgrp);
+       spin_unlock_irqrestore(&pty->ctrl_lock, flags);
+
+       if (pgrp)
+               kill_pgrp(pgrp, SIGWINCH, 1);
+       if (rpgrp != pgrp && rpgrp)
+               kill_pgrp(rpgrp, SIGWINCH, 1);
+
+       put_pid(pgrp);
+       put_pid(rpgrp);
+
+       tty->winsize = *ws;
+       pty->winsize = *ws;     /* Never used so will go away soon */
+done:
+       mutex_unlock(&tty->termios_mutex);
+       return 0;
+}
+
 static int pty_install(struct tty_driver *driver, struct tty_struct *tty)
 {
        struct tty_struct *o_tty;
@@ -290,6 +336,7 @@ static const struct tty_operations pty_ops = {
        .chars_in_buffer = pty_chars_in_buffer,
        .unthrottle = pty_unthrottle,
        .set_termios = pty_set_termios,
+       .resize = pty_resize
 };
 
 /* Traditional BSD devices */
@@ -319,6 +366,7 @@ static const struct tty_operations pty_ops_bsd = {
        .unthrottle = pty_unthrottle,
        .set_termios = pty_set_termios,
        .ioctl = pty_bsd_ioctl,
+       .resize = pty_resize
 };
 
 static void __init legacy_pty_init(void)
@@ -561,7 +609,8 @@ static const struct tty_operations ptm_unix98_ops = {
        .unthrottle = pty_unthrottle,
        .set_termios = pty_set_termios,
        .ioctl = pty_unix98_ioctl,
-       .shutdown = pty_unix98_shutdown
+       .shutdown = pty_unix98_shutdown,
+       .resize = pty_resize
 };
 
 static const struct tty_operations pty_unix98_ops = {
index a8f68a3f14dd56e4beea33c06407f51d39cc62a1..2e8a6eed34be59039c57fbb6151973b8c19c9c3d 100644 (file)
@@ -173,7 +173,7 @@ static void rio_disable_tx_interrupts(void *ptr);
 static void rio_enable_tx_interrupts(void *ptr);
 static void rio_disable_rx_interrupts(void *ptr);
 static void rio_enable_rx_interrupts(void *ptr);
-static int rio_get_CD(void *ptr);
+static int rio_carrier_raised(struct tty_port *port);
 static void rio_shutdown_port(void *ptr);
 static int rio_set_real_termios(void *ptr);
 static void rio_hungup(void *ptr);
@@ -224,7 +224,6 @@ static struct real_driver rio_real_driver = {
        rio_enable_tx_interrupts,
        rio_disable_rx_interrupts,
        rio_enable_rx_interrupts,
-       rio_get_CD,
        rio_shutdown_port,
        rio_set_real_termios,
        rio_chars_in_buffer,
@@ -476,9 +475,9 @@ static void rio_enable_rx_interrupts(void *ptr)
 
 
 /* Jeez. Isn't this simple?  */
-static int rio_get_CD(void *ptr)
+static int rio_carrier_raised(struct tty_port *port)
 {
-       struct Port *PortP = ptr;
+       struct Port *PortP = container_of(port, struct Port, gs.port);
        int rv;
 
        func_enter();
@@ -797,16 +796,9 @@ static int rio_init_drivers(void)
        return 1;
 }
 
-
-static void *ckmalloc(int size)
-{
-       void *p;
-
-       p = kzalloc(size, GFP_KERNEL);
-       return p;
-}
-
-
+static const struct tty_port_operations rio_port_ops = {
+       .carrier_raised = rio_carrier_raised,
+};
 
 static int rio_init_datastructures(void)
 {
@@ -826,33 +818,30 @@ static int rio_init_datastructures(void)
 #define TMIO_SZ sizeof(struct termios *)
        rio_dprintk(RIO_DEBUG_INIT, "getting : %Zd %Zd %Zd %Zd %Zd bytes\n", RI_SZ, RIO_HOSTS * HOST_SZ, RIO_PORTS * PORT_SZ, RIO_PORTS * TMIO_SZ, RIO_PORTS * TMIO_SZ);
 
-       if (!(p = ckmalloc(RI_SZ)))
+       if (!(p = kzalloc(RI_SZ, GFP_KERNEL)))
                goto free0;
-       if (!(p->RIOHosts = ckmalloc(RIO_HOSTS * HOST_SZ)))
+       if (!(p->RIOHosts = kzalloc(RIO_HOSTS * HOST_SZ, GFP_KERNEL)))
                goto free1;
-       if (!(p->RIOPortp = ckmalloc(RIO_PORTS * PORT_SZ)))
+       if (!(p->RIOPortp = kzalloc(RIO_PORTS * PORT_SZ, GFP_KERNEL)))
                goto free2;
        p->RIOConf = RIOConf;
        rio_dprintk(RIO_DEBUG_INIT, "Got : %p %p %p\n", p, p->RIOHosts, p->RIOPortp);
 
 #if 1
        for (i = 0; i < RIO_PORTS; i++) {
-               port = p->RIOPortp[i] = ckmalloc(sizeof(struct Port));
+               port = p->RIOPortp[i] = kzalloc(sizeof(struct Port), GFP_KERNEL);
                if (!port) {
                        goto free6;
                }
                rio_dprintk(RIO_DEBUG_INIT, "initing port %d (%d)\n", i, port->Mapped);
+               tty_port_init(&port->gs.port);
+               port->gs.port.ops = &rio_port_ops;
                port->PortNum = i;
                port->gs.magic = RIO_MAGIC;
                port->gs.close_delay = HZ / 2;
                port->gs.closing_wait = 30 * HZ;
                port->gs.rd = &rio_real_driver;
                spin_lock_init(&port->portSem);
-               /*
-                * Initializing wait queue
-                */
-               init_waitqueue_head(&port->gs.port.open_wait);
-               init_waitqueue_head(&port->gs.port.close_wait);
        }
 #else
        /* We could postpone initializing them to when they are configured. */
index 2c6c8f33d6b43e7dda4d7b03fb8f0615698d0bb3..9af8d74875bc9e24cb76f97528647532036d7712 100644 (file)
@@ -857,98 +857,21 @@ static void rc_shutdown_port(struct tty_struct *tty,
                rc_shutdown_board(bp);
 }
 
-static int block_til_ready(struct tty_struct *tty, struct file *filp,
-                          struct riscom_port *port)
+static int carrier_raised(struct tty_port *port)
 {
-       DECLARE_WAITQUEUE(wait, current);
-       struct riscom_board *bp = port_Board(port);
-       int    retval;
-       int    do_clocal = 0;
-       int    CD;
+       struct riscom_port *p = container_of(port, struct riscom_port, port);
+       struct riscom_board *bp = port_Board(p);
        unsigned long flags;
-
-       /*
-        * 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->port.flags & ASYNC_CLOSING) {
-               interruptible_sleep_on(&port->port.close_wait);
-               if (port->port.flags & ASYNC_HUP_NOTIFY)
-                       return -EAGAIN;
-               else
-                       return -ERESTARTSYS;
-       }
-
-       /*
-        * 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->port.flags |= ASYNC_NORMAL_ACTIVE;
-               return 0;
-       }
-
-       if (C_CLOCAL(tty))
-               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, info->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->port.open_wait, &wait);
-
+       int CD;
+       
        spin_lock_irqsave(&riscom_lock, flags);
-
-       if (!tty_hung_up_p(filp))
-               port->port.count--;
-
+       rc_out(bp, CD180_CAR, port_No(p));
+       CD = rc_in(bp, CD180_MSVR) & MSVR_CD;
+       rc_out(bp, CD180_MSVR, MSVR_RTS);
+       bp->DTR &= ~(1u << port_No(p));
+       rc_out(bp, RC_DTR, bp->DTR);
        spin_unlock_irqrestore(&riscom_lock, flags);
-
-       port->port.blocked_open++;
-       while (1) {
-               spin_lock_irqsave(&riscom_lock, flags);
-
-               rc_out(bp, CD180_CAR, port_No(port));
-               CD = rc_in(bp, CD180_MSVR) & MSVR_CD;
-               rc_out(bp, CD180_MSVR, MSVR_RTS);
-               bp->DTR &= ~(1u << port_No(port));
-               rc_out(bp, RC_DTR, bp->DTR);
-
-               spin_unlock_irqrestore(&riscom_lock, flags);
-
-               set_current_state(TASK_INTERRUPTIBLE);
-               if (tty_hung_up_p(filp) ||
-                   !(port->port.flags & ASYNC_INITIALIZED)) {
-                       if (port->port.flags & ASYNC_HUP_NOTIFY)
-                               retval = -EAGAIN;
-                       else
-                               retval = -ERESTARTSYS;
-                       break;
-               }
-               if (!(port->port.flags & ASYNC_CLOSING) &&
-                   (do_clocal || CD))
-                       break;
-               if (signal_pending(current)) {
-                       retval = -ERESTARTSYS;
-                       break;
-               }
-               schedule();
-       }
-       __set_current_state(TASK_RUNNING);
-       remove_wait_queue(&port->port.open_wait, &wait);
-       if (!tty_hung_up_p(filp))
-               port->port.count++;
-       port->port.blocked_open--;
-       if (retval)
-               return retval;
-
-       port->port.flags |= ASYNC_NORMAL_ACTIVE;
-       return 0;
+       return CD;
 }
 
 static int rc_open(struct tty_struct *tty, struct file *filp)
@@ -977,13 +900,13 @@ static int rc_open(struct tty_struct *tty, struct file *filp)
 
        error = rc_setup_port(bp, port);
        if (error == 0)
-               error = block_til_ready(tty, filp, port);
+               error = tty_port_block_til_ready(&port->port, tty, filp);
        return error;
 }
 
 static void rc_flush_buffer(struct tty_struct *tty)
 {
-       struct riscom_port *port = (struct riscom_port *)tty->driver_data;
+       struct riscom_port *port = tty->driver_data;
        unsigned long flags;
 
        if (rc_paranoia_check(port, tty->name, "rc_flush_buffer"))
@@ -998,7 +921,7 @@ static void rc_flush_buffer(struct tty_struct *tty)
 
 static void rc_close(struct tty_struct *tty, struct file *filp)
 {
-       struct riscom_port *port = (struct riscom_port *) tty->driver_data;
+       struct riscom_port *port = tty->driver_data;
        struct riscom_board *bp;
        unsigned long flags;
        unsigned long timeout;
@@ -1006,40 +929,19 @@ static void rc_close(struct tty_struct *tty, struct file *filp)
        if (!port || rc_paranoia_check(port, tty->name, "close"))
                return;
 
-       spin_lock_irqsave(&riscom_lock, flags);
-
-       if (tty_hung_up_p(filp))
-               goto out;
-
        bp = port_Board(port);
-       if ((tty->count == 1) && (port->port.count != 1))  {
-               printk(KERN_INFO "rc%d: rc_close: bad port count;"
-                      " tty->count is 1, port count is %d\n",
-                      board_No(bp), port->port.count);
-               port->port.count = 1;
-       }
-       if (--port->port.count < 0)  {
-               printk(KERN_INFO "rc%d: rc_close: bad port count "
-                                "for tty%d: %d\n",
-                      board_No(bp), port_No(port), port->port.count);
-               port->port.count = 0;
-       }
-       if (port->port.count)
-               goto out;
-       port->port.flags |= ASYNC_CLOSING;
-       /*
-        * Now we wait for the transmit buffer to clear; and we notify
-        * the line discipline to only process XON/XOFF characters.
-        */
-       tty->closing = 1;
-       if (port->port.closing_wait != ASYNC_CLOSING_WAIT_NONE)
-               tty_wait_until_sent(tty, port->port.closing_wait);
+       
+       if (tty_port_close_start(&port->port, tty, filp) == 0)
+               return;
+       
        /*
         * 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.
         */
+
+       spin_lock_irqsave(&riscom_lock, flags);
        port->IER &= ~IER_RXD;
        if (port->port.flags & ASYNC_INITIALIZED) {
                port->IER &= ~IER_TXRDY;
@@ -1053,33 +955,24 @@ static void rc_close(struct tty_struct *tty, struct file *filp)
                 */
                timeout = jiffies + HZ;
                while (port->IER & IER_TXEMPTY) {
+                       spin_unlock_irqrestore(&riscom_lock, flags);
                        msleep_interruptible(jiffies_to_msecs(port->timeout));
+                       spin_lock_irqsave(&riscom_lock, flags);
                        if (time_after(jiffies, timeout))
                                break;
                }
        }
        rc_shutdown_port(tty, bp, port);
        rc_flush_buffer(tty);
-       tty_ldisc_flush(tty);
-
-       tty->closing = 0;
-       port->port.tty = NULL;
-       if (port->port.blocked_open) {
-               if (port->port.close_delay)
-                       msleep_interruptible(jiffies_to_msecs(port->port.close_delay));
-               wake_up_interruptible(&port->port.open_wait);
-       }
-       port->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
-       wake_up_interruptible(&port->port.close_wait);
-
-out:
        spin_unlock_irqrestore(&riscom_lock, flags);
+
+       tty_port_close_end(&port->port, tty);
 }
 
 static int rc_write(struct tty_struct *tty,
                    const unsigned char *buf, int count)
 {
-       struct riscom_port *port = (struct riscom_port *)tty->driver_data;
+       struct riscom_port *port = tty->driver_data;
        struct riscom_board *bp;
        int c, total = 0;
        unsigned long flags;
@@ -1122,7 +1015,7 @@ static int rc_write(struct tty_struct *tty,
 
 static int rc_put_char(struct tty_struct *tty, unsigned char ch)
 {
-       struct riscom_port *port = (struct riscom_port *)tty->driver_data;
+       struct riscom_port *port = tty->driver_data;
        unsigned long flags;
        int ret = 0;
 
@@ -1146,7 +1039,7 @@ out:
 
 static void rc_flush_chars(struct tty_struct *tty)
 {
-       struct riscom_port *port = (struct riscom_port *)tty->driver_data;
+       struct riscom_port *port = tty->driver_data;
        unsigned long flags;
 
        if (rc_paranoia_check(port, tty->name, "rc_flush_chars"))
@@ -1166,7 +1059,7 @@ static void rc_flush_chars(struct tty_struct *tty)
 
 static int rc_write_room(struct tty_struct *tty)
 {
-       struct riscom_port *port = (struct riscom_port *)tty->driver_data;
+       struct riscom_port *port = tty->driver_data;
        int     ret;
 
        if (rc_paranoia_check(port, tty->name, "rc_write_room"))
@@ -1180,7 +1073,7 @@ static int rc_write_room(struct tty_struct *tty)
 
 static int rc_chars_in_buffer(struct tty_struct *tty)
 {
-       struct riscom_port *port = (struct riscom_port *)tty->driver_data;
+       struct riscom_port *port = tty->driver_data;
 
        if (rc_paranoia_check(port, tty->name, "rc_chars_in_buffer"))
                return 0;
@@ -1190,7 +1083,7 @@ static int rc_chars_in_buffer(struct tty_struct *tty)
 
 static int rc_tiocmget(struct tty_struct *tty, struct file *file)
 {
-       struct riscom_port *port = (struct riscom_port *)tty->driver_data;
+       struct riscom_port *port = tty->driver_data;
        struct riscom_board *bp;
        unsigned char status;
        unsigned int result;
@@ -1220,7 +1113,7 @@ static int rc_tiocmget(struct tty_struct *tty, struct file *file)
 static int rc_tiocmset(struct tty_struct *tty, struct file *file,
                       unsigned int set, unsigned int clear)
 {
-       struct riscom_port *port = (struct riscom_port *)tty->driver_data;
+       struct riscom_port *port = tty->driver_data;
        unsigned long flags;
        struct riscom_board *bp;
 
@@ -1252,7 +1145,7 @@ static int rc_tiocmset(struct tty_struct *tty, struct file *file,
 
 static int rc_send_break(struct tty_struct *tty, int length)
 {
-       struct riscom_port *port = (struct riscom_port *)tty->driver_data;
+       struct riscom_port *port = tty->driver_data;
        struct riscom_board *bp = port_Board(port);
        unsigned long flags;
 
@@ -1345,7 +1238,7 @@ static int rc_get_serial_info(struct riscom_port *port,
 static int rc_ioctl(struct tty_struct *tty, struct file *filp,
                    unsigned int cmd, unsigned long arg)
 {
-       struct riscom_port *port = (struct riscom_port *)tty->driver_data;
+       struct riscom_port *port = tty->driver_data;
        void __user *argp = (void __user *)arg;
        int retval;
 
@@ -1371,7 +1264,7 @@ static int rc_ioctl(struct tty_struct *tty, struct file *filp,
 
 static void rc_throttle(struct tty_struct *tty)
 {
-       struct riscom_port *port = (struct riscom_port *)tty->driver_data;
+       struct riscom_port *port = tty->driver_data;
        struct riscom_board *bp;
        unsigned long flags;
 
@@ -1393,7 +1286,7 @@ static void rc_throttle(struct tty_struct *tty)
 
 static void rc_unthrottle(struct tty_struct *tty)
 {
-       struct riscom_port *port = (struct riscom_port *)tty->driver_data;
+       struct riscom_port *port = tty->driver_data;
        struct riscom_board *bp;
        unsigned long flags;
 
@@ -1415,7 +1308,7 @@ static void rc_unthrottle(struct tty_struct *tty)
 
 static void rc_stop(struct tty_struct *tty)
 {
-       struct riscom_port *port = (struct riscom_port *)tty->driver_data;
+       struct riscom_port *port = tty->driver_data;
        struct riscom_board *bp;
        unsigned long flags;
 
@@ -1433,7 +1326,7 @@ static void rc_stop(struct tty_struct *tty)
 
 static void rc_start(struct tty_struct *tty)
 {
-       struct riscom_port *port = (struct riscom_port *)tty->driver_data;
+       struct riscom_port *port = tty->driver_data;
        struct riscom_board *bp;
        unsigned long flags;
 
@@ -1454,8 +1347,9 @@ static void rc_start(struct tty_struct *tty)
 
 static void rc_hangup(struct tty_struct *tty)
 {
-       struct riscom_port *port = (struct riscom_port *)tty->driver_data;
+       struct riscom_port *port = tty->driver_data;
        struct riscom_board *bp;
+       unsigned long flags;
 
        if (rc_paranoia_check(port, tty->name, "rc_hangup"))
                return;
@@ -1463,16 +1357,18 @@ static void rc_hangup(struct tty_struct *tty)
        bp = port_Board(port);
 
        rc_shutdown_port(tty, bp, port);
+       spin_lock_irqsave(&port->port.lock, flags);
        port->port.count = 0;
        port->port.flags &= ~ASYNC_NORMAL_ACTIVE;
        port->port.tty = NULL;
        wake_up_interruptible(&port->port.open_wait);
+       spin_unlock_irqrestore(&port->port.lock, flags);
 }
 
 static void rc_set_termios(struct tty_struct *tty,
                                        struct ktermios *old_termios)
 {
-       struct riscom_port *port = (struct riscom_port *)tty->driver_data;
+       struct riscom_port *port = tty->driver_data;
        unsigned long flags;
 
        if (rc_paranoia_check(port, tty->name, "rc_set_termios"))
@@ -1510,6 +1406,11 @@ static const struct tty_operations riscom_ops = {
        .break_ctl = rc_send_break,
 };
 
+static const struct tty_port_operations riscom_port_ops = {
+       .carrier_raised = carrier_raised,
+};
+
+
 static int __init rc_init_drivers(void)
 {
        int error;
@@ -1541,6 +1442,7 @@ static int __init rc_init_drivers(void)
        memset(rc_port, 0, sizeof(rc_port));
        for (i = 0; i < RC_NPORT * RC_NBOARD; i++)  {
                tty_port_init(&rc_port[i].port);
+               rc_port[i].port.ops = &riscom_port_ops;
                rc_port[i].magic = RISCOM8_MAGIC;
        }
        return 0;
index 584d791e84a6ed85634e359d76dfd4bfaeb397d4..f59fc5cea0673546fa03b0395a8d12b6f7872ff4 100644 (file)
@@ -135,6 +135,7 @@ static int rcktpt_type[NUM_BOARDS];
 static int is_PCI[NUM_BOARDS];
 static rocketModel_t rocketModel[NUM_BOARDS];
 static int max_board;
+static const struct tty_port_operations rocket_port_ops;
 
 /*
  * The following arrays define the interrupt bits corresponding to each AIOP.
@@ -435,15 +436,15 @@ static void rp_do_transmit(struct r_port *info)
 #endif
        if (!info)
                return;
-       if (!info->port.tty) {
-               printk(KERN_WARNING "rp: WARNING %s called with "
-                               "info->port.tty==NULL\n", __func__);
+       tty = tty_port_tty_get(&info->port);
+
+       if (tty == NULL) {
+               printk(KERN_WARNING "rp: WARNING %s called with tty==NULL\n", __func__);
                clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
                return;
        }
 
        spin_lock_irqsave(&info->slock, flags);
-       tty = info->port.tty;
        info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);
 
        /*  Loop sending data to FIFO until done or FIFO full */
@@ -477,6 +478,7 @@ static void rp_do_transmit(struct r_port *info)
        }
 
        spin_unlock_irqrestore(&info->slock, flags);
+       tty_kref_put(tty);
 
 #ifdef ROCKET_DEBUG_INTR
        printk(KERN_DEBUG "(%d,%d,%d,%d)...\n", info->xmit_cnt, info->xmit_head,
@@ -498,18 +500,18 @@ static void rp_handle_port(struct r_port *info)
        if (!info)
                return;
 
-       if ((info->flags & ROCKET_INITIALIZED) == 0) {
+       if ((info->port.flags & ASYNC_INITIALIZED) == 0) {
                printk(KERN_WARNING "rp: WARNING: rp_handle_port called with "
                                "info->flags & NOT_INIT\n");
                return;
        }
-       if (!info->port.tty) {
+       tty = tty_port_tty_get(&info->port);
+       if (!tty) {
                printk(KERN_WARNING "rp: WARNING: rp_handle_port called with "
-                               "info->port.tty==NULL\n");
+                               "tty==NULL\n");
                return;
        }
        cp = &info->channel;
-       tty = info->port.tty;
 
        IntMask = sGetChanIntID(cp) & info->intmask;
 #ifdef ROCKET_DEBUG_INTR
@@ -541,6 +543,7 @@ static void rp_handle_port(struct r_port *info)
                printk(KERN_INFO "DSR change...\n");
        }
 #endif
+       tty_kref_put(tty);
 }
 
 /*
@@ -649,9 +652,8 @@ static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev)
        info->board = board;
        info->aiop = aiop;
        info->chan = chan;
-       info->port.closing_wait = 3000;
-       info->port.close_delay = 50;
-       init_waitqueue_head(&info->port.open_wait);
+       tty_port_init(&info->port);
+       info->port.ops = &rocket_port_ops;
        init_completion(&info->close_wait);
        info->flags &= ~ROCKET_MODE_MASK;
        switch (pc104[board][line]) {
@@ -710,7 +712,7 @@ static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev)
  *  Configures a rocketport port according to its termio settings.  Called from 
  *  user mode into the driver (exception handler).  *info CD manipulation is spinlock protected.
  */
-static void configure_r_port(struct r_port *info,
+static void configure_r_port(struct tty_struct *tty, struct r_port *info,
                             struct ktermios *old_termios)
 {
        unsigned cflag;
@@ -718,7 +720,7 @@ static void configure_r_port(struct r_port *info,
        unsigned rocketMode;
        int bits, baud, divisor;
        CHANNEL_t *cp;
-       struct ktermios *t = info->port.tty->termios;
+       struct ktermios *t = tty->termios;
 
        cp = &info->channel;
        cflag = t->c_cflag;
@@ -751,7 +753,7 @@ static void configure_r_port(struct r_port *info,
        }
 
        /* baud rate */
-       baud = tty_get_baud_rate(info->port.tty);
+       baud = tty_get_baud_rate(tty);
        if (!baud)
                baud = 9600;
        divisor = ((rp_baud_base[info->board] + (baud >> 1)) / baud) - 1;
@@ -769,7 +771,7 @@ static void configure_r_port(struct r_port *info,
        sSetBaud(cp, divisor);
 
        /* FIXME: Should really back compute a baud rate from the divisor */
-       tty_encode_baud_rate(info->port.tty, baud, baud);
+       tty_encode_baud_rate(tty, baud, baud);
 
        if (cflag & CRTSCTS) {
                info->intmask |= DELTA_CTS;
@@ -794,15 +796,15 @@ static void configure_r_port(struct r_port *info,
         * Handle software flow control in the board
         */
 #ifdef ROCKET_SOFT_FLOW
-       if (I_IXON(info->port.tty)) {
+       if (I_IXON(tty)) {
                sEnTxSoftFlowCtl(cp);
-               if (I_IXANY(info->port.tty)) {
+               if (I_IXANY(tty)) {
                        sEnIXANY(cp);
                } else {
                        sDisIXANY(cp);
                }
-               sSetTxXONChar(cp, START_CHAR(info->port.tty));
-               sSetTxXOFFChar(cp, STOP_CHAR(info->port.tty));
+               sSetTxXONChar(cp, START_CHAR(tty));
+               sSetTxXOFFChar(cp, STOP_CHAR(tty));
        } else {
                sDisTxSoftFlowCtl(cp);
                sDisIXANY(cp);
@@ -814,24 +816,24 @@ static void configure_r_port(struct r_port *info,
         * Set up ignore/read mask words
         */
        info->read_status_mask = STMRCVROVRH | 0xFF;
-       if (I_INPCK(info->port.tty))
+       if (I_INPCK(tty))
                info->read_status_mask |= STMFRAMEH | STMPARITYH;
-       if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty))
+       if (I_BRKINT(tty) || I_PARMRK(tty))
                info->read_status_mask |= STMBREAKH;
 
        /*
         * Characters to ignore
         */
        info->ignore_status_mask = 0;
-       if (I_IGNPAR(info->port.tty))
+       if (I_IGNPAR(tty))
                info->ignore_status_mask |= STMFRAMEH | STMPARITYH;
-       if (I_IGNBRK(info->port.tty)) {
+       if (I_IGNBRK(tty)) {
                info->ignore_status_mask |= STMBREAKH;
                /*
                 * If we're ignoring parity and break indicators,
                 * ignore overruns too.  (For real raw support).
                 */
-               if (I_IGNPAR(info->port.tty))
+               if (I_IGNPAR(tty))
                        info->ignore_status_mask |= STMRCVROVRH;
        }
 
@@ -864,106 +866,17 @@ static void configure_r_port(struct r_port *info,
        }
 }
 
-/*  info->port.count is considered critical, protected by spinlocks.  */
-static int block_til_ready(struct tty_struct *tty, struct file *filp,
-                          struct r_port *info)
+static int carrier_raised(struct tty_port *port)
 {
-       DECLARE_WAITQUEUE(wait, current);
-       int retval;
-       int do_clocal = 0, extra_count = 0;
-       unsigned long flags;
-
-       /*
-        * 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))
-               return ((info->flags & ROCKET_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS);
-       if (info->flags & ROCKET_CLOSING) {
-               if (wait_for_completion_interruptible(&info->close_wait))
-                       return -ERESTARTSYS;
-               return ((info->flags & ROCKET_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS);
-       }
-
-       /*
-        * 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))) {
-               info->flags |= ROCKET_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.  While we are in
-        * this loop, info->port.count is dropped by one, so that rp_close() knows when to free things.
-         * We restore it upon exit, either normal or abnormal.
-        */
-       retval = 0;
-       add_wait_queue(&info->port.open_wait, &wait);
-#ifdef ROCKET_DEBUG_OPEN
-       printk(KERN_INFO "block_til_ready before block: ttyR%d, count = %d\n", info->line, info->port.count);
-#endif
-       spin_lock_irqsave(&info->slock, flags);
-
-#ifdef ROCKET_DISABLE_SIMUSAGE
-       info->flags |= ROCKET_NORMAL_ACTIVE;
-#else
-       if (!tty_hung_up_p(filp)) {
-               extra_count = 1;
-               info->port.count--;
-       }
-#endif
-       info->port.blocked_open++;
-
-       spin_unlock_irqrestore(&info->slock, flags);
-
-       while (1) {
-               if (tty->termios->c_cflag & CBAUD) {
-                       sSetDTR(&info->channel);
-                       sSetRTS(&info->channel);
-               }
-               set_current_state(TASK_INTERRUPTIBLE);
-               if (tty_hung_up_p(filp) || !(info->flags & ROCKET_INITIALIZED)) {
-                       if (info->flags & ROCKET_HUP_NOTIFY)
-                               retval = -EAGAIN;
-                       else
-                               retval = -ERESTARTSYS;
-                       break;
-               }
-               if (!(info->flags & ROCKET_CLOSING) && (do_clocal || (sGetChanStatusLo(&info->channel) & CD_ACT)))
-                       break;
-               if (signal_pending(current)) {
-                       retval = -ERESTARTSYS;
-                       break;
-               }
-#ifdef ROCKET_DEBUG_OPEN
-               printk(KERN_INFO "block_til_ready blocking: ttyR%d, count = %d, flags=0x%0x\n",
-                    info->line, info->port.count, info->flags);
-#endif
-               schedule();     /*  Don't hold spinlock here, will hang PC */
-       }
-       __set_current_state(TASK_RUNNING);
-       remove_wait_queue(&info->port.open_wait, &wait);
-
-       spin_lock_irqsave(&info->slock, flags);
-
-       if (extra_count)
-               info->port.count++;
-       info->port.blocked_open--;
-
-       spin_unlock_irqrestore(&info->slock, flags);
+       struct r_port *info = container_of(port, struct r_port, port);
+       return (sGetChanStatusLo(&info->channel) & CD_ACT) ? 1 : 0;
+}
 
-#ifdef ROCKET_DEBUG_OPEN
-       printk(KERN_INFO "block_til_ready after blocking: ttyR%d, count = %d\n",
-              info->line, info->port.count);
-#endif
-       if (retval)
-               return retval;
-       info->flags |= ROCKET_NORMAL_ACTIVE;
-       return 0;
+static void raise_dtr_rts(struct tty_port *port)
+{
+       struct r_port *info = container_of(port, struct r_port, port);
+       sSetDTR(&info->channel);
+       sSetRTS(&info->channel);
 }
 
 /*
@@ -973,24 +886,26 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
 static int rp_open(struct tty_struct *tty, struct file *filp)
 {
        struct r_port *info;
+       struct tty_port *port;
        int line = 0, retval;
        CHANNEL_t *cp;
        unsigned long page;
 
        line = tty->index;
-       if ((line < 0) || (line >= MAX_RP_PORTS) || ((info = rp_table[line]) == NULL))
+       if (line < 0 || line >= MAX_RP_PORTS || ((info = rp_table[line]) == NULL))
                return -ENXIO;
-
+       port = &info->port;
+       
        page = __get_free_page(GFP_KERNEL);
        if (!page)
                return -ENOMEM;
 
-       if (info->flags & ROCKET_CLOSING) {
+       if (port->flags & ASYNC_CLOSING) {
                retval = wait_for_completion_interruptible(&info->close_wait);
                free_page(page);
                if (retval)
                        return retval;
-               return ((info->flags & ROCKET_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS);
+               return ((port->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS);
        }
 
        /*
@@ -1002,9 +917,9 @@ static int rp_open(struct tty_struct *tty, struct file *filp)
                info->xmit_buf = (unsigned char *) page;
 
        tty->driver_data = info;
-       info->port.tty = tty;
+       tty_port_tty_set(port, tty);
 
-       if (info->port.count++ == 0) {
+       if (port->count++ == 0) {
                atomic_inc(&rp_num_ports_open);
 
 #ifdef ROCKET_DEBUG_OPEN
@@ -1019,7 +934,7 @@ static int rp_open(struct tty_struct *tty, struct file *filp)
        /*
         * Info->count is now 1; so it's safe to sleep now.
         */
-       if ((info->flags & ROCKET_INITIALIZED) == 0) {
+       if (!test_bit(ASYNC_INITIALIZED, &port->flags)) {
                cp = &info->channel;
                sSetRxTrigger(cp, TRIG_1);
                if (sGetChanStatus(cp) & CD_ACT)
@@ -1043,21 +958,21 @@ static int rp_open(struct tty_struct *tty, struct file *filp)
                sEnRxFIFO(cp);
                sEnTransmit(cp);
 
-               info->flags |= ROCKET_INITIALIZED;
+               set_bit(ASYNC_INITIALIZED, &info->port.flags);
 
                /*
                 * Set up the tty->alt_speed kludge
                 */
                if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI)
-                       info->port.tty->alt_speed = 57600;
+                       tty->alt_speed = 57600;
                if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI)
-                       info->port.tty->alt_speed = 115200;
+                       tty->alt_speed = 115200;
                if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI)
-                       info->port.tty->alt_speed = 230400;
+                       tty->alt_speed = 230400;
                if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP)
-                       info->port.tty->alt_speed = 460800;
+                       tty->alt_speed = 460800;
 
-               configure_r_port(info, NULL);
+               configure_r_port(tty, info, NULL);
                if (tty->termios->c_cflag & CBAUD) {
                        sSetDTR(cp);
                        sSetRTS(cp);
@@ -1066,7 +981,7 @@ static int rp_open(struct tty_struct *tty, struct file *filp)
        /*  Starts (or resets) the maint polling loop */
        mod_timer(&rocket_timer, jiffies + POLL_PERIOD);
 
-       retval = block_til_ready(tty, filp, info);
+       retval = tty_port_block_til_ready(port, tty, filp);
        if (retval) {
 #ifdef ROCKET_DEBUG_OPEN
                printk(KERN_INFO "rp_open returning after block_til_ready with %d\n", retval);
@@ -1081,8 +996,8 @@ static int rp_open(struct tty_struct *tty, struct file *filp)
  */
 static void rp_close(struct tty_struct *tty, struct file *filp)
 {
-       struct r_port *info = (struct r_port *) tty->driver_data;
-       unsigned long flags;
+       struct r_port *info = tty->driver_data;
+       struct tty_port *port = &info->port;
        int timeout;
        CHANNEL_t *cp;
        
@@ -1093,53 +1008,10 @@ static void rp_close(struct tty_struct *tty, struct file *filp)
        printk(KERN_INFO "rp_close ttyR%d, count = %d\n", info->line, info->port.count);
 #endif
 
-       if (tty_hung_up_p(filp))
-               return;
-       spin_lock_irqsave(&info->slock, flags);
-
-       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_WARNING "rp_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_WARNING "rp_close: bad serial port count for "
-                               "ttyR%d: %d\n", info->line, info->port.count);
-               info->port.count = 0;
-       }
-       if (info->port.count) {
-               spin_unlock_irqrestore(&info->slock, flags);
+       if (tty_port_close_start(port, tty, filp) == 0)
                return;
-       }
-       info->flags |= ROCKET_CLOSING;
-       spin_unlock_irqrestore(&info->slock, flags);
 
        cp = &info->channel;
-
-       /*
-        * Notify the line discpline to only process XON/XOFF characters
-        */
-       tty->closing = 1;
-
-       /*
-        * If transmission was throttled by the application request,
-        * just flush the xmit buffer.
-        */
-       if (tty->flow_stopped)
-               rp_flush_buffer(tty);
-
-       /*
-        * Wait for the transmit buffer to clear
-        */
-       if (info->port.closing_wait != ROCKET_CLOSING_WAIT_NONE)
-               tty_wait_until_sent(tty, info->port.closing_wait);
        /*
         * Before we drop DTR, make sure the UART transmitter
         * has completely drained; this is especially
@@ -1168,19 +1040,24 @@ static void rp_close(struct tty_struct *tty, struct file *filp)
 
        clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
 
-       if (info->port.blocked_open) {
-               if (info->port.close_delay) {
-                       msleep_interruptible(jiffies_to_msecs(info->port.close_delay));
+       /* We can't yet use tty_port_close_end as the buffer handling in this
+          driver is a bit different to the usual */
+
+       if (port->blocked_open) {
+               if (port->close_delay) {
+                       msleep_interruptible(jiffies_to_msecs(port->close_delay));
                }
-               wake_up_interruptible(&info->port.open_wait);
+               wake_up_interruptible(&port->open_wait);
        } else {
                if (info->xmit_buf) {
                        free_page((unsigned long) info->xmit_buf);
                        info->xmit_buf = NULL;
                }
        }
-       info->flags &= ~(ROCKET_INITIALIZED | ROCKET_CLOSING | ROCKET_NORMAL_ACTIVE);
+       info->port.flags &= ~(ASYNC_INITIALIZED | ASYNC_CLOSING | ASYNC_NORMAL_ACTIVE);
        tty->closing = 0;
+       tty_port_tty_set(port, NULL);
+       wake_up_interruptible(&port->close_wait);
        complete_all(&info->close_wait);
        atomic_dec(&rp_num_ports_open);
 
@@ -1195,7 +1072,7 @@ static void rp_close(struct tty_struct *tty, struct file *filp)
 static void rp_set_termios(struct tty_struct *tty,
                           struct ktermios *old_termios)
 {
-       struct r_port *info = (struct r_port *) tty->driver_data;
+       struct r_port *info = tty->driver_data;
        CHANNEL_t *cp;
        unsigned cflag;
 
@@ -1213,7 +1090,7 @@ static void rp_set_termios(struct tty_struct *tty,
        /* Or CMSPAR */
        tty->termios->c_cflag &= ~CMSPAR;
 
-       configure_r_port(info, old_termios);
+       configure_r_port(tty, info, old_termios);
 
        cp = &info->channel;
 
@@ -1238,7 +1115,7 @@ static void rp_set_termios(struct tty_struct *tty,
 
 static int rp_break(struct tty_struct *tty, int break_state)
 {
-       struct r_port *info = (struct r_port *) tty->driver_data;
+       struct r_port *info = tty->driver_data;
        unsigned long flags;
 
        if (rocket_paranoia_check(info, "rp_break"))
@@ -1284,7 +1161,7 @@ static int sGetChanRI(CHANNEL_T * ChP)
  */
 static int rp_tiocmget(struct tty_struct *tty, struct file *file)
 {
-       struct r_port *info = (struct r_port *)tty->driver_data;
+       struct r_port *info = tty->driver_data;
        unsigned int control, result, ChanStatus;
 
        ChanStatus = sGetChanStatusLo(&info->channel);
@@ -1305,7 +1182,7 @@ static int rp_tiocmget(struct tty_struct *tty, struct file *file)
 static int rp_tiocmset(struct tty_struct *tty, struct file *file,
                    unsigned int set, unsigned int clear)
 {
-       struct r_port *info = (struct r_port *)tty->driver_data;
+       struct r_port *info = tty->driver_data;
 
        if (set & TIOCM_RTS)
                info->channel.TxControl[3] |= SET_RTS;
@@ -1338,7 +1215,8 @@ static int get_config(struct r_port *info, struct rocket_config __user *retinfo)
        return 0;
 }
 
-static int set_config(struct r_port *info, struct rocket_config __user *new_info)
+static int set_config(struct tty_struct *tty, struct r_port *info,
+                                       struct rocket_config __user *new_info)
 {
        struct rocket_config new_serial;
 
@@ -1350,7 +1228,7 @@ static int set_config(struct r_port *info, struct rocket_config __user *new_info
                if ((new_serial.flags & ~ROCKET_USR_MASK) != (info->flags & ~ROCKET_USR_MASK))
                        return -EPERM;
                info->flags = ((info->flags & ~ROCKET_USR_MASK) | (new_serial.flags & ROCKET_USR_MASK));
-               configure_r_port(info, NULL);
+               configure_r_port(tty, info, NULL);
                return 0;
        }
 
@@ -1359,15 +1237,15 @@ static int set_config(struct r_port *info, struct rocket_config __user *new_info
        info->port.closing_wait = new_serial.closing_wait;
 
        if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI)
-               info->port.tty->alt_speed = 57600;
+               tty->alt_speed = 57600;
        if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI)
-               info->port.tty->alt_speed = 115200;
+               tty->alt_speed = 115200;
        if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI)
-               info->port.tty->alt_speed = 230400;
+               tty->alt_speed = 230400;
        if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP)
-               info->port.tty->alt_speed = 460800;
+               tty->alt_speed = 460800;
 
-       configure_r_port(info, NULL);
+       configure_r_port(tty, info, NULL);
        return 0;
 }
 
@@ -1434,7 +1312,7 @@ static int get_version(struct r_port *info, struct rocket_version __user *retver
 static int rp_ioctl(struct tty_struct *tty, struct file *file,
                    unsigned int cmd, unsigned long arg)
 {
-       struct r_port *info = (struct r_port *) tty->driver_data;
+       struct r_port *info = tty->driver_data;
        void __user *argp = (void __user *)arg;
        int ret = 0;
 
@@ -1452,7 +1330,7 @@ static int rp_ioctl(struct tty_struct *tty, struct file *file,
                ret = get_config(info, argp);
                break;
        case RCKP_SET_CONFIG:
-               ret = set_config(info, argp);
+               ret = set_config(tty, info, argp);
                break;
        case RCKP_GET_PORTS:
                ret = get_ports(info, argp);
@@ -1472,7 +1350,7 @@ static int rp_ioctl(struct tty_struct *tty, struct file *file,
 
 static void rp_send_xchar(struct tty_struct *tty, char ch)
 {
-       struct r_port *info = (struct r_port *) tty->driver_data;
+       struct r_port *info = tty->driver_data;
        CHANNEL_t *cp;
 
        if (rocket_paranoia_check(info, "rp_send_xchar"))
@@ -1487,7 +1365,7 @@ static void rp_send_xchar(struct tty_struct *tty, char ch)
 
 static void rp_throttle(struct tty_struct *tty)
 {
-       struct r_port *info = (struct r_port *) tty->driver_data;
+       struct r_port *info = tty->driver_data;
        CHANNEL_t *cp;
 
 #ifdef ROCKET_DEBUG_THROTTLE
@@ -1507,7 +1385,7 @@ static void rp_throttle(struct tty_struct *tty)
 
 static void rp_unthrottle(struct tty_struct *tty)
 {
-       struct r_port *info = (struct r_port *) tty->driver_data;
+       struct r_port *info = tty->driver_data;
        CHANNEL_t *cp;
 #ifdef ROCKET_DEBUG_THROTTLE
        printk(KERN_INFO "unthrottle %s: %d....\n", tty->name,
@@ -1534,7 +1412,7 @@ static void rp_unthrottle(struct tty_struct *tty)
  */
 static void rp_stop(struct tty_struct *tty)
 {
-       struct r_port *info = (struct r_port *) tty->driver_data;
+       struct r_port *info = tty->driver_data;
 
 #ifdef ROCKET_DEBUG_FLOW
        printk(KERN_INFO "stop %s: %d %d....\n", tty->name,
@@ -1550,7 +1428,7 @@ static void rp_stop(struct tty_struct *tty)
 
 static void rp_start(struct tty_struct *tty)
 {
-       struct r_port *info = (struct r_port *) tty->driver_data;
+       struct r_port *info = tty->driver_data;
 
 #ifdef ROCKET_DEBUG_FLOW
        printk(KERN_INFO "start %s: %d %d....\n", tty->name,
@@ -1570,7 +1448,7 @@ static void rp_start(struct tty_struct *tty)
  */
 static void rp_wait_until_sent(struct tty_struct *tty, int timeout)
 {
-       struct r_port *info = (struct r_port *) tty->driver_data;
+       struct r_port *info = tty->driver_data;
        CHANNEL_t *cp;
        unsigned long orig_jiffies;
        int check_time, exit_time;
@@ -1627,7 +1505,7 @@ static void rp_wait_until_sent(struct tty_struct *tty, int timeout)
 static void rp_hangup(struct tty_struct *tty)
 {
        CHANNEL_t *cp;
-       struct r_port *info = (struct r_port *) tty->driver_data;
+       struct r_port *info = tty->driver_data;
 
        if (rocket_paranoia_check(info, "rp_hangup"))
                return;
@@ -1636,15 +1514,13 @@ static void rp_hangup(struct tty_struct *tty)
        printk(KERN_INFO "rp_hangup of ttyR%d...\n", info->line);
 #endif
        rp_flush_buffer(tty);
-       if (info->flags & ROCKET_CLOSING)
+       if (info->port.flags & ASYNC_CLOSING)
                return;
        if (info->port.count)
                atomic_dec(&rp_num_ports_open);
        clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
 
-       info->port.count = 0;
-       info->flags &= ~ROCKET_NORMAL_ACTIVE;
-       info->port.tty = NULL;
+       tty_port_hangup(&info->port);
 
        cp = &info->channel;
        sDisRxFIFO(cp);
@@ -1653,7 +1529,7 @@ static void rp_hangup(struct tty_struct *tty)
        sDisCTSFlowCtl(cp);
        sDisTxSoftFlowCtl(cp);
        sClrTxXOFF(cp);
-       info->flags &= ~ROCKET_INITIALIZED;
+       info->port.flags &= ~ASYNC_INITIALIZED;
 
        wake_up_interruptible(&info->port.open_wait);
 }
@@ -1667,7 +1543,7 @@ static void rp_hangup(struct tty_struct *tty)
  */
 static int rp_put_char(struct tty_struct *tty, unsigned char ch)
 {
-       struct r_port *info = (struct r_port *) tty->driver_data;
+       struct r_port *info = tty->driver_data;
        CHANNEL_t *cp;
        unsigned long flags;
 
@@ -1714,7 +1590,7 @@ static int rp_put_char(struct tty_struct *tty, unsigned char ch)
 static int rp_write(struct tty_struct *tty,
                    const unsigned char *buf, int count)
 {
-       struct r_port *info = (struct r_port *) tty->driver_data;
+       struct r_port *info = tty->driver_data;
        CHANNEL_t *cp;
        const unsigned char *b;
        int c, retval = 0;
@@ -1764,7 +1640,8 @@ static int rp_write(struct tty_struct *tty,
 
        /*  Write remaining data into the port's xmit_buf */
        while (1) {
-               if (!info->port.tty)            /* Seemingly obligatory check... */
+               /* Hung up ? */
+               if (!test_bit(ASYNC_NORMAL_ACTIVE, &info->port.flags))
                        goto end;
                c = min(count, XMIT_BUF_SIZE - info->xmit_cnt - 1);
                c = min(c, XMIT_BUF_SIZE - info->xmit_head);
@@ -1806,7 +1683,7 @@ end:
  */
 static int rp_write_room(struct tty_struct *tty)
 {
-       struct r_port *info = (struct r_port *) tty->driver_data;
+       struct r_port *info = tty->driver_data;
        int ret;
 
        if (rocket_paranoia_check(info, "rp_write_room"))
@@ -1827,7 +1704,7 @@ static int rp_write_room(struct tty_struct *tty)
  */
 static int rp_chars_in_buffer(struct tty_struct *tty)
 {
-       struct r_port *info = (struct r_port *) tty->driver_data;
+       struct r_port *info = tty->driver_data;
        CHANNEL_t *cp;
 
        if (rocket_paranoia_check(info, "rp_chars_in_buffer"))
@@ -1848,7 +1725,7 @@ static int rp_chars_in_buffer(struct tty_struct *tty)
  */
 static void rp_flush_buffer(struct tty_struct *tty)
 {
-       struct r_port *info = (struct r_port *) tty->driver_data;
+       struct r_port *info = tty->driver_data;
        CHANNEL_t *cp;
        unsigned long flags;
 
@@ -2371,6 +2248,11 @@ static const struct tty_operations rocket_ops = {
        .tiocmset = rp_tiocmset,
 };
 
+static const struct tty_port_operations rocket_port_ops = {
+       .carrier_raised = carrier_raised,
+       .raise_dtr_rts = raise_dtr_rts,
+};
+
 /*
  * The module "startup" routine; it's run when the module is loaded.
  */
index a8b09195ebba8b8d4c4a089fc23ef805d829ade0..ec863f35f1a974e41cc8871b4c9a4d8e1a2766a8 100644 (file)
@@ -39,7 +39,7 @@ struct rocket_version {
 /*
  * Rocketport flags
  */
-#define ROCKET_CALLOUT_NOHUP    0x00000001
+/*#define ROCKET_CALLOUT_NOHUP    0x00000001 */
 #define ROCKET_FORCE_CD                0x00000002
 #define ROCKET_HUP_NOTIFY      0x00000004
 #define ROCKET_SPLIT_TERMIOS   0x00000008
index 21f3ff53ba3206ec3d37524d520658b10387f66c..67e0f1e778a23d4804de496d22759549966b914c 100644 (file)
@@ -1162,11 +1162,6 @@ struct r_port {
 /* number of characters left in xmit buffer before we ask for more */
 #define WAKEUP_CHARS 256
 
-/* Internal flags used only by the rocketport driver */
-#define ROCKET_INITIALIZED     0x80000000      /* Port is active */
-#define ROCKET_CLOSING         0x40000000      /* Serial port is closing */
-#define ROCKET_NORMAL_ACTIVE   0x20000000      /* Normal port is active */
-
 /*
  * Assigned major numbers for the Comtrol Rocketport
  */
index 2978a49a172b0cdba3d91814fd3b68b614645fea..f29fbe9b8ed7f27d775902a245d5a79d34f4e515 100644 (file)
@@ -306,7 +306,7 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t
  */
 int paste_selection(struct tty_struct *tty)
 {
-       struct vc_data *vc = (struct vc_data *)tty->driver_data;
+       struct vc_data *vc = tty->driver_data;
        int     pasted = 0;
        unsigned int count;
        struct  tty_ldisc *ld;
index 7b0c35207d9b4fb034b3414d6a9b4788830d7cac..33872a219df6b57355f5dd1eb5e988f9e8bb89d3 100644 (file)
@@ -122,7 +122,7 @@ static void a2232_disable_tx_interrupts(void *ptr);
 static void a2232_enable_tx_interrupts(void *ptr);
 static void a2232_disable_rx_interrupts(void *ptr);
 static void a2232_enable_rx_interrupts(void *ptr);
-static int  a2232_get_CD(void *ptr);
+static int  a2232_carrier_raised(struct tty_port *port);
 static void a2232_shutdown_port(void *ptr);
 static int  a2232_set_real_termios(void *ptr);
 static int  a2232_chars_in_buffer(void *ptr);
@@ -148,7 +148,6 @@ static struct real_driver a2232_real_driver = {
         a2232_enable_tx_interrupts,
         a2232_disable_rx_interrupts,
         a2232_enable_rx_interrupts,
-        a2232_get_CD,
         a2232_shutdown_port,
         a2232_set_real_termios,
         a2232_chars_in_buffer,
@@ -260,9 +259,10 @@ static void a2232_enable_rx_interrupts(void *ptr)
        port->disable_rx = 0;
 }
 
-static int  a2232_get_CD(void *ptr)
+static int  a2232_carrier_raised(struct tty_port *port)
 {
-       return ((struct a2232_port *) ptr)->cd_status;
+       struct a2232_port *ap = container_of(port, struct a2232_port, gs.port);
+       return ap->cd_status;
 }
 
 static void a2232_shutdown_port(void *ptr)
@@ -460,14 +460,14 @@ static void a2232_throttle(struct tty_struct *tty)
    if switched on. So the only thing we can do at this
    layer here is not taking any characters out of the
    A2232 buffer any more. */
-       struct a2232_port *port = (struct a2232_port *) tty->driver_data;
+       struct a2232_port *port = tty->driver_data;
        port->throttle_input = -1;
 }
 
 static void a2232_unthrottle(struct tty_struct *tty)
 {
 /* Unthrottle: dual to "throttle()" above. */
-       struct a2232_port *port = (struct a2232_port *) tty->driver_data;
+       struct a2232_port *port = tty->driver_data;
        port->throttle_input = 0;
 }
 
@@ -638,6 +638,10 @@ int ch, err, n, p;
        return IRQ_HANDLED;
 }
 
+static const struct tty_port_operations a2232_port_ops = {
+       .carrier_raised = a2232_carrier_raised,
+};
+
 static void a2232_init_portstructs(void)
 {
        struct a2232_port *port;
@@ -645,6 +649,8 @@ static void a2232_init_portstructs(void)
 
        for (i = 0; i < MAX_A2232_BOARDS*NUMLINES; i++) {
                port = a2232_ports + i;
+               tty_port_init(&port->gs.port);
+               port->gs.port.ops = &a2232_port_ops;
                port->which_a2232 = i/NUMLINES;
                port->which_port_on_a2232 = i%NUMLINES;
                port->disable_rx = port->throttle_input = port->cd_status = 0;
@@ -652,11 +658,6 @@ static void a2232_init_portstructs(void)
                port->gs.close_delay = HZ/2;
                port->gs.closing_wait = 30 * HZ;
                port->gs.rd = &a2232_real_driver;
-#ifdef NEW_WRITE_LOCKING
-               mutex_init(&(port->gs.port_write_mutex));
-#endif
-               init_waitqueue_head(&port->gs.port.open_wait);
-               init_waitqueue_head(&port->gs.port.close_wait);
        }
 }
 
index a8f15e6be594237f150b1b3e92ad1b9a7d468ae1..f1f24f0ee26f4281392925b0d86b4ad4a5e897af 100644 (file)
@@ -315,7 +315,7 @@ u_short write_cy_cmd(volatile u_char * base_addr, u_char cmd)
 
 static void cy_stop(struct tty_struct *tty)
 {
-       struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+       struct cyclades_port *info = tty->driver_data;
        volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
        int channel;
        unsigned long flags;
@@ -337,7 +337,7 @@ static void cy_stop(struct tty_struct *tty)
 
 static void cy_start(struct tty_struct *tty)
 {
-       struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+       struct cyclades_port *info = tty->driver_data;
        volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
        int channel;
        unsigned long flags;
@@ -1062,7 +1062,7 @@ static void config_setup(struct cyclades_port *info)
 
 static int cy_put_char(struct tty_struct *tty, unsigned char ch)
 {
-       struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+       struct cyclades_port *info = tty->driver_data;
        unsigned long flags;
 
 #ifdef SERIAL_DEBUG_IO
@@ -1090,7 +1090,7 @@ static int cy_put_char(struct tty_struct *tty, unsigned char ch)
 
 static void cy_flush_chars(struct tty_struct *tty)
 {
-       struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+       struct cyclades_port *info = tty->driver_data;
        unsigned long flags;
        volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
        int channel;
@@ -1122,7 +1122,7 @@ static void cy_flush_chars(struct tty_struct *tty)
  */
 static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
 {
-       struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+       struct cyclades_port *info = tty->driver_data;
        unsigned long flags;
        int c, total = 0;
 
@@ -1166,7 +1166,7 @@ static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
 
 static int cy_write_room(struct tty_struct *tty)
 {
-       struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+       struct cyclades_port *info = tty->driver_data;
        int ret;
 
 #ifdef SERIAL_DEBUG_IO
@@ -1183,7 +1183,7 @@ static int cy_write_room(struct tty_struct *tty)
 
 static int cy_chars_in_buffer(struct tty_struct *tty)
 {
-       struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+       struct cyclades_port *info = tty->driver_data;
 
 #ifdef SERIAL_DEBUG_IO
        printk("cy_chars_in_buffer %s %d\n", tty->name, info->xmit_cnt);        /* */
@@ -1197,7 +1197,7 @@ static int cy_chars_in_buffer(struct tty_struct *tty)
 
 static void cy_flush_buffer(struct tty_struct *tty)
 {
-       struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+       struct cyclades_port *info = tty->driver_data;
        unsigned long flags;
 
 #ifdef SERIAL_DEBUG_IO
@@ -1218,7 +1218,7 @@ static void cy_flush_buffer(struct tty_struct *tty)
  */
 static void cy_throttle(struct tty_struct *tty)
 {
-       struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+       struct cyclades_port *info = tty->driver_data;
        unsigned long flags;
        volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
        int channel;
@@ -1250,7 +1250,7 @@ static void cy_throttle(struct tty_struct *tty)
 
 static void cy_unthrottle(struct tty_struct *tty)
 {
-       struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+       struct cyclades_port *info = tty->driver_data;
        unsigned long flags;
        volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
        int channel;
@@ -1345,7 +1345,7 @@ check_and_exit:
 
 static int cy_tiocmget(struct tty_struct *tty, struct file *file)
 {
-       struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+       struct cyclades_port *info = tty->driver_data;
        int channel;
        volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
        unsigned long flags;
@@ -1369,7 +1369,7 @@ static int
 cy_tiocmset(struct tty_struct *tty, struct file *file,
            unsigned int set, unsigned int clear)
 {
-       struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+       struct cyclades_port *info = tty->driver_data;
        int channel;
        volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
        unsigned long flags;
@@ -1532,7 +1532,7 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
         unsigned int cmd, unsigned long arg)
 {
        unsigned long val;
-       struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+       struct cyclades_port *info = tty->driver_data;
        int ret_val = 0;
        void __user *argp = (void __user *)arg;
 
@@ -1607,7 +1607,7 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
 
 static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
 {
-       struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+       struct cyclades_port *info = tty->driver_data;
 
 #ifdef SERIAL_DEBUG_OTHER
        printk("cy_set_termios %s\n", tty->name);
@@ -1631,7 +1631,7 @@ static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
 
 static void cy_close(struct tty_struct *tty, struct file *filp)
 {
-       struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+       struct cyclades_port *info = tty->driver_data;
 
 /* CP('C'); */
 #ifdef SERIAL_DEBUG_OTHER
@@ -1698,7 +1698,7 @@ static void cy_close(struct tty_struct *tty, struct file *filp)
  */
 void cy_hangup(struct tty_struct *tty)
 {
-       struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+       struct cyclades_port *info = tty->driver_data;
 
 #ifdef SERIAL_DEBUG_OTHER
        printk("cy_hangup %s\n", tty->name);    /* */
index a16b94f12eb23e1fea8b99bfd6621a0b1bc8b7cd..3c67c3d83de9c2962ab6dc76936848b5ca28dd76 100644 (file)
@@ -1450,7 +1450,7 @@ static int sx_open(struct tty_struct *tty, struct file *filp)
 
 static void sx_flush_buffer(struct tty_struct *tty)
 {
-       struct specialix_port *port = (struct specialix_port *)tty->driver_data;
+       struct specialix_port *port = tty->driver_data;
        unsigned long flags;
        struct specialix_board  *bp;
 
@@ -1472,7 +1472,7 @@ static void sx_flush_buffer(struct tty_struct *tty)
 
 static void sx_close(struct tty_struct *tty, struct file *filp)
 {
-       struct specialix_port *port = (struct specialix_port *)tty->driver_data;
+       struct specialix_port *port = tty->driver_data;
        struct specialix_board *bp;
        unsigned long flags;
        unsigned long timeout;
@@ -1585,7 +1585,7 @@ static void sx_close(struct tty_struct *tty, struct file *filp)
 static int sx_write(struct tty_struct *tty,
                                        const unsigned char *buf, int count)
 {
-       struct specialix_port *port = (struct specialix_port *)tty->driver_data;
+       struct specialix_port *port = tty->driver_data;
        struct specialix_board *bp;
        int c, total = 0;
        unsigned long flags;
@@ -1637,7 +1637,7 @@ static int sx_write(struct tty_struct *tty,
 
 static int sx_put_char(struct tty_struct *tty, unsigned char ch)
 {
-       struct specialix_port *port = (struct specialix_port *)tty->driver_data;
+       struct specialix_port *port = tty->driver_data;
        unsigned long flags;
        struct specialix_board  *bp;
 
@@ -1676,7 +1676,7 @@ static int sx_put_char(struct tty_struct *tty, unsigned char ch)
 
 static void sx_flush_chars(struct tty_struct *tty)
 {
-       struct specialix_port *port = (struct specialix_port *)tty->driver_data;
+       struct specialix_port *port = tty->driver_data;
        unsigned long flags;
        struct specialix_board  *bp = port_Board(port);
 
@@ -1703,7 +1703,7 @@ static void sx_flush_chars(struct tty_struct *tty)
 
 static int sx_write_room(struct tty_struct *tty)
 {
-       struct specialix_port *port = (struct specialix_port *)tty->driver_data;
+       struct specialix_port *port = tty->driver_data;
        int     ret;
 
        func_enter();
@@ -1724,7 +1724,7 @@ static int sx_write_room(struct tty_struct *tty)
 
 static int sx_chars_in_buffer(struct tty_struct *tty)
 {
-       struct specialix_port *port = (struct specialix_port *)tty->driver_data;
+       struct specialix_port *port = tty->driver_data;
 
        func_enter();
 
@@ -1738,7 +1738,7 @@ static int sx_chars_in_buffer(struct tty_struct *tty)
 
 static int sx_tiocmget(struct tty_struct *tty, struct file *file)
 {
-       struct specialix_port *port = (struct specialix_port *)tty->driver_data;
+       struct specialix_port *port = tty->driver_data;
        struct specialix_board *bp;
        unsigned char status;
        unsigned int result;
@@ -1780,7 +1780,7 @@ static int sx_tiocmget(struct tty_struct *tty, struct file *file)
 static int sx_tiocmset(struct tty_struct *tty, struct file *file,
                       unsigned int set, unsigned int clear)
 {
-       struct specialix_port *port = (struct specialix_port *)tty->driver_data;
+       struct specialix_port *port = tty->driver_data;
        unsigned long flags;
        struct specialix_board *bp;
 
@@ -1820,7 +1820,7 @@ static int sx_tiocmset(struct tty_struct *tty, struct file *file,
 
 static int sx_send_break(struct tty_struct *tty, int length)
 {
-       struct specialix_port *port = (struct specialix_port *)tty->driver_data;
+       struct specialix_port *port = tty->driver_data;
        struct specialix_board *bp = port_Board(port);
        unsigned long flags;
 
@@ -1931,7 +1931,7 @@ static int sx_get_serial_info(struct specialix_port *port,
 static int sx_ioctl(struct tty_struct *tty, struct file *filp,
                                unsigned int cmd, unsigned long arg)
 {
-       struct specialix_port *port = (struct specialix_port *)tty->driver_data;
+       struct specialix_port *port = tty->driver_data;
        void __user *argp = (void __user *)arg;
 
        func_enter();
@@ -1959,7 +1959,7 @@ static int sx_ioctl(struct tty_struct *tty, struct file *filp,
 
 static void sx_throttle(struct tty_struct *tty)
 {
-       struct specialix_port *port = (struct specialix_port *)tty->driver_data;
+       struct specialix_port *port = tty->driver_data;
        struct specialix_board *bp;
        unsigned long flags;
 
@@ -2004,7 +2004,7 @@ static void sx_throttle(struct tty_struct *tty)
 
 static void sx_unthrottle(struct tty_struct *tty)
 {
-       struct specialix_port *port = (struct specialix_port *)tty->driver_data;
+       struct specialix_port *port = tty->driver_data;
        struct specialix_board *bp;
        unsigned long flags;
 
@@ -2045,7 +2045,7 @@ static void sx_unthrottle(struct tty_struct *tty)
 
 static void sx_stop(struct tty_struct *tty)
 {
-       struct specialix_port *port = (struct specialix_port *)tty->driver_data;
+       struct specialix_port *port = tty->driver_data;
        struct specialix_board *bp;
        unsigned long flags;
 
@@ -2072,7 +2072,7 @@ static void sx_stop(struct tty_struct *tty)
 
 static void sx_start(struct tty_struct *tty)
 {
-       struct specialix_port *port = (struct specialix_port *)tty->driver_data;
+       struct specialix_port *port = tty->driver_data;
        struct specialix_board *bp;
        unsigned long flags;
 
@@ -2100,7 +2100,7 @@ static void sx_start(struct tty_struct *tty)
 
 static void sx_hangup(struct tty_struct *tty)
 {
-       struct specialix_port *port = (struct specialix_port *)tty->driver_data;
+       struct specialix_port *port = tty->driver_data;
        struct specialix_board *bp;
        unsigned long flags;
 
@@ -2135,7 +2135,7 @@ static void sx_hangup(struct tty_struct *tty)
 static void sx_set_termios(struct tty_struct *tty,
                                        struct ktermios *old_termios)
 {
-       struct specialix_port *port = (struct specialix_port *)tty->driver_data;
+       struct specialix_port *port = tty->driver_data;
        unsigned long flags;
        struct specialix_board  *bp;
 
index 963b03fb29e5583aa45e83f056c6cf1ff412ba43..e1e0dd89ac9aa309e2f92c9183618948b09b6900 100644 (file)
@@ -130,6 +130,8 @@ static char         stl_unwanted[SC26198_RXFIFOSIZE];
 static DEFINE_MUTEX(stl_brdslock);
 static struct stlbrd           *stl_brds[STL_MAXBRDS];
 
+static const struct tty_port_operations stl_port_ops;
+
 /*
  *     Per board state flags. Used with the state field of the board struct.
  *     Not really much here!
@@ -407,7 +409,6 @@ static int  stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, uns
 static int     stl_brdinit(struct stlbrd *brdp);
 static int     stl_getportstats(struct tty_struct *tty, struct stlport *portp, comstats_t __user *cp);
 static int     stl_clrportstats(struct stlport *portp, comstats_t __user *cp);
-static int     stl_waitcarrier(struct tty_struct *tty, struct stlport *portp, struct file *filp);
 
 /*
  *     CD1400 uart specific handling functions.
@@ -703,8 +704,9 @@ static int stl_open(struct tty_struct *tty, struct file *filp)
 {
        struct stlport  *portp;
        struct stlbrd   *brdp;
+       struct tty_port *port;
        unsigned int    minordev, brdnr, panelnr;
-       int             portnr, rc;
+       int             portnr;
 
        pr_debug("stl_open(tty=%p,filp=%p): device=%s\n", tty, filp, tty->name);
 
@@ -715,6 +717,7 @@ static int stl_open(struct tty_struct *tty, struct file *filp)
        brdp = stl_brds[brdnr];
        if (brdp == NULL)
                return -ENODEV;
+
        minordev = MINOR2PORT(minordev);
        for (portnr = -1, panelnr = 0; panelnr < STL_MAXPANELS; panelnr++) {
                if (brdp->panels[panelnr] == NULL)
@@ -731,16 +734,17 @@ static int stl_open(struct tty_struct *tty, struct file *filp)
        portp = brdp->panels[panelnr]->ports[portnr];
        if (portp == NULL)
                return -ENODEV;
+       port = &portp->port;
 
 /*
  *     On the first open of the device setup the port hardware, and
  *     initialize the per port data structure.
  */
-       tty_port_tty_set(&portp->port, tty);
+       tty_port_tty_set(port, tty);
        tty->driver_data = portp;
-       portp->port.count++;
+       port->count++;
 
-       if ((portp->port.flags & ASYNC_INITIALIZED) == 0) {
+       if ((port->flags & ASYNC_INITIALIZED) == 0) {
                if (!portp->tx.buf) {
                        portp->tx.buf = kmalloc(STL_TXBUFSIZE, GFP_KERNEL);
                        if (!portp->tx.buf)
@@ -754,91 +758,24 @@ static int stl_open(struct tty_struct *tty, struct file *filp)
                stl_enablerxtx(portp, 1, 1);
                stl_startrxtx(portp, 1, 0);
                clear_bit(TTY_IO_ERROR, &tty->flags);
-               portp->port.flags |= ASYNC_INITIALIZED;
-       }
-
-/*
- *     Check if this port is in the middle of closing. If so then wait
- *     until it is closed then return error status, based on flag settings.
- *     The sleep here does not need interrupt protection since the wakeup
- *     for it is done with the same context.
- */
-       if (portp->port.flags & ASYNC_CLOSING) {
-               interruptible_sleep_on(&portp->port.close_wait);
-               if (portp->port.flags & ASYNC_HUP_NOTIFY)
-                       return -EAGAIN;
-               return -ERESTARTSYS;
+               port->flags |= ASYNC_INITIALIZED;
        }
-
-/*
- *     Based on type of open being done check if it can overlap with any
- *     previous opens still in effect. If we are a normal serial device
- *     then also we might have to wait for carrier.
- */
-       if (!(filp->f_flags & O_NONBLOCK))
-               if ((rc = stl_waitcarrier(tty, portp, filp)) != 0)
-                       return rc;
-
-       portp->port.flags |= ASYNC_NORMAL_ACTIVE;
-
-       return 0;
+       return tty_port_block_til_ready(port, tty, filp);
 }
 
 /*****************************************************************************/
 
-/*
- *     Possibly need to wait for carrier (DCD signal) to come high. Say
- *     maybe because if we are clocal then we don't need to wait...
- */
-
-static int stl_waitcarrier(struct tty_struct *tty, struct stlport *portp,
-                                                       struct file *filp)
+static int stl_carrier_raised(struct tty_port *port)
 {
-       unsigned long   flags;
-       int             rc, doclocal;
-
-       pr_debug("stl_waitcarrier(portp=%p,filp=%p)\n", portp, filp);
-
-       rc = 0;
-       doclocal = 0;
-
-       spin_lock_irqsave(&stallion_lock, flags);
-
-       if (tty->termios->c_cflag & CLOCAL)
-               doclocal++;
-
-       portp->openwaitcnt++;
-       if (! tty_hung_up_p(filp))
-               portp->port.count--;
-
-       for (;;) {
-               /* Takes brd_lock internally */
-               stl_setsignals(portp, 1, 1);
-               if (tty_hung_up_p(filp) ||
-                   ((portp->port.flags & ASYNC_INITIALIZED) == 0)) {
-                       if (portp->port.flags & ASYNC_HUP_NOTIFY)
-                               rc = -EBUSY;
-                       else
-                               rc = -ERESTARTSYS;
-                       break;
-               }
-               if (((portp->port.flags & ASYNC_CLOSING) == 0) &&
-                   (doclocal || (portp->sigs & TIOCM_CD)))
-                       break;
-               if (signal_pending(current)) {
-                       rc = -ERESTARTSYS;
-                       break;
-               }
-               /* FIXME */
-               interruptible_sleep_on(&portp->port.open_wait);
-       }
-
-       if (! tty_hung_up_p(filp))
-               portp->port.count++;
-       portp->openwaitcnt--;
-       spin_unlock_irqrestore(&stallion_lock, flags);
+       struct stlport *portp = container_of(port, struct stlport, port);
+       return (portp->sigs & TIOCM_CD) ? 1 : 0;
+}
 
-       return rc;
+static void stl_raise_dtr_rts(struct tty_port *port)
+{
+       struct stlport *portp = container_of(port, struct stlport, port);
+       /* Takes brd_lock internally */
+       stl_setsignals(portp, 1, 1);
 }
 
 /*****************************************************************************/
@@ -890,47 +827,29 @@ static void stl_waituntilsent(struct tty_struct *tty, int timeout)
 static void stl_close(struct tty_struct *tty, struct file *filp)
 {
        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;
-       if (portp == NULL)
-               return;
+       BUG_ON(portp == NULL);
 
-       spin_lock_irqsave(&stallion_lock, flags);
-       if (tty_hung_up_p(filp)) {
-               spin_unlock_irqrestore(&stallion_lock, flags);
-               return;
-       }
-       if ((tty->count == 1) && (portp->port.count != 1))
-               portp->port.count = 1;
-       if (portp->port.count-- > 1) {
-               spin_unlock_irqrestore(&stallion_lock, flags);
-               return;
-       }
-
-       portp->port.count = 0;
-       portp->port.flags |= ASYNC_CLOSING;
+       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)
  */
-       tty->closing = 1;
-
-       spin_unlock_irqrestore(&stallion_lock, flags);
-
-       if (portp->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-               tty_wait_until_sent(tty, portp->closing_wait);
        stl_waituntilsent(tty, (HZ / 2));
 
-
-       spin_lock_irqsave(&stallion_lock, flags);
+       spin_lock_irqsave(&port->lock, flags);
        portp->port.flags &= ~ASYNC_INITIALIZED;
-       spin_unlock_irqrestore(&stallion_lock, flags);
+       spin_unlock_irqrestore(&port->lock, flags);
 
        stl_disableintrs(portp);
        if (tty->termios->c_cflag & HUPCL)
@@ -944,20 +863,9 @@ static void stl_close(struct tty_struct *tty, struct file *filp)
                portp->tx.head = NULL;
                portp->tx.tail = NULL;
        }
-       set_bit(TTY_IO_ERROR, &tty->flags);
-       tty_ldisc_flush(tty);
 
-       tty->closing = 0;
-       tty_port_tty_set(&portp->port, NULL);
-
-       if (portp->openwaitcnt) {
-               if (portp->close_delay)
-                       msleep_interruptible(jiffies_to_msecs(portp->close_delay));
-               wake_up_interruptible(&portp->port.open_wait);
-       }
-
-       portp->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
-       wake_up_interruptible(&portp->port.close_wait);
+       tty_port_close_end(port, tty);
+       tty_port_tty_set(port, NULL);
 }
 
 /*****************************************************************************/
@@ -1405,14 +1313,20 @@ static void stl_stop(struct tty_struct *tty)
 static void stl_hangup(struct tty_struct *tty)
 {
        struct stlport  *portp;
+       struct tty_port *port;
+       unsigned long flags;
 
        pr_debug("stl_hangup(tty=%p)\n", tty);
 
        portp = tty->driver_data;
        if (portp == NULL)
                return;
+       port = &portp->port;
+
+       spin_lock_irqsave(&port->lock, flags);
+       port->flags &= ~ASYNC_INITIALIZED;
+       spin_unlock_irqrestore(&port->lock, flags);
 
-       portp->port.flags &= ~ASYNC_INITIALIZED;
        stl_disableintrs(portp);
        if (tty->termios->c_cflag & HUPCL)
                stl_setsignals(portp, 0, 0);
@@ -1426,10 +1340,7 @@ static void stl_hangup(struct tty_struct *tty)
                portp->tx.head = NULL;
                portp->tx.tail = NULL;
        }
-       tty_port_tty_set(&portp->port, NULL);
-       portp->port.flags &= ~ASYNC_NORMAL_ACTIVE;
-       portp->port.count = 0;
-       wake_up_interruptible(&portp->port.open_wait);
+       tty_port_hangup(port);
 }
 
 /*****************************************************************************/
@@ -1776,6 +1687,7 @@ static int __devinit stl_initports(struct stlbrd *brdp, struct stlpanel *panelp)
                        break;
                }
                tty_port_init(&portp->port);
+               portp->port.ops = &stl_port_ops;
                portp->magic = STL_PORTMAGIC;
                portp->portnr = i;
                portp->brdnr = panelp->brdnr;
@@ -2659,6 +2571,11 @@ static const struct tty_operations stl_ops = {
        .tiocmset = stl_tiocmset,
 };
 
+static const struct tty_port_operations stl_port_ops = {
+       .carrier_raised = stl_carrier_raised,
+       .raise_dtr_rts = stl_raise_dtr_rts,
+};
+
 /*****************************************************************************/
 /*                       CD1400 HARDWARE FUNCTIONS                           */
 /*****************************************************************************/
index ba4e86281fbf29dde6dc9b121da6228628f22d33..b60be7b0decf277f3220898a27906ed0c4d7e79b 100644 (file)
@@ -279,7 +279,7 @@ static void sx_disable_tx_interrupts(void *ptr);
 static void sx_enable_tx_interrupts(void *ptr);
 static void sx_disable_rx_interrupts(void *ptr);
 static void sx_enable_rx_interrupts(void *ptr);
-static int sx_get_CD(void *ptr);
+static int sx_carrier_raised(struct tty_port *port);
 static void sx_shutdown_port(void *ptr);
 static int sx_set_real_termios(void *ptr);
 static void sx_close(void *ptr);
@@ -360,7 +360,6 @@ static struct real_driver sx_real_driver = {
        sx_enable_tx_interrupts,
        sx_disable_rx_interrupts,
        sx_enable_rx_interrupts,
-       sx_get_CD,
        sx_shutdown_port,
        sx_set_real_termios,
        sx_chars_in_buffer,
@@ -791,7 +790,7 @@ static int sx_getsignals(struct sx_port *port)
        sx_dprintk(SX_DEBUG_MODEMSIGNALS, "getsignals: %d/%d  (%d/%d) "
                        "%02x/%02x\n",
                        (o_stat & OP_DTR) != 0, (o_stat & OP_RTS) != 0,
-                       port->c_dcd, sx_get_CD(port),
+                       port->c_dcd, tty_port_carrier_raised(&port->gs.port),
                        sx_read_channel_byte(port, hi_ip),
                        sx_read_channel_byte(port, hi_state));
 
@@ -1190,7 +1189,7 @@ static inline void sx_check_modem_signals(struct sx_port *port)
 
        hi_state = sx_read_channel_byte(port, hi_state);
        sx_dprintk(SX_DEBUG_MODEMSIGNALS, "Checking modem signals (%d/%d)\n",
-                       port->c_dcd, sx_get_CD(port));
+                       port->c_dcd, tty_port_carrier_raised(&port->gs.port));
 
        if (hi_state & ST_BREAK) {
                hi_state &= ~ST_BREAK;
@@ -1202,11 +1201,11 @@ static inline void sx_check_modem_signals(struct sx_port *port)
                hi_state &= ~ST_DCD;
                sx_dprintk(SX_DEBUG_MODEMSIGNALS, "got a DCD change.\n");
                sx_write_channel_byte(port, hi_state, hi_state);
-               c_dcd = sx_get_CD(port);
+               c_dcd = tty_port_carrier_raised(&port->gs.port);
                sx_dprintk(SX_DEBUG_MODEMSIGNALS, "DCD is now %d\n", c_dcd);
                if (c_dcd != port->c_dcd) {
                        port->c_dcd = c_dcd;
-                       if (sx_get_CD(port)) {
+                       if (tty_port_carrier_raised(&port->gs.port)) {
                                /* DCD went UP */
                                if ((sx_read_channel_byte(port, hi_hstat) !=
                                                HS_IDLE_CLOSED) &&
@@ -1415,13 +1414,10 @@ static void sx_enable_rx_interrupts(void *ptr)
 }
 
 /* Jeez. Isn't this simple? */
-static int sx_get_CD(void *ptr)
+static int sx_carrier_raised(struct tty_port *port)
 {
-       struct sx_port *port = ptr;
-       func_enter2();
-
-       func_exit();
-       return ((sx_read_channel_byte(port, hi_ip) & IP_DCD) != 0);
+       struct sx_port *sp = container_of(port, struct sx_port, gs.port);
+       return ((sx_read_channel_byte(sp, hi_ip) & IP_DCD) != 0);
 }
 
 /* Jeez. Isn't this simple? */
@@ -1536,7 +1532,7 @@ static int sx_open(struct tty_struct *tty, struct file *filp)
        }
        /* tty->low_latency = 1; */
 
-       port->c_dcd = sx_get_CD(port);
+       port->c_dcd = sx_carrier_raised(&port->gs.port);
        sx_dprintk(SX_DEBUG_OPEN, "at open: cd=%d\n", port->c_dcd);
 
        func_exit();
@@ -1945,7 +1941,7 @@ static int sx_ioctl(struct tty_struct *tty, struct file *filp,
 
 static void sx_throttle(struct tty_struct *tty)
 {
-       struct sx_port *port = (struct sx_port *)tty->driver_data;
+       struct sx_port *port = tty->driver_data;
 
        func_enter2();
        /* If the port is using any type of input flow
@@ -1959,7 +1955,7 @@ static void sx_throttle(struct tty_struct *tty)
 
 static void sx_unthrottle(struct tty_struct *tty)
 {
-       struct sx_port *port = (struct sx_port *)tty->driver_data;
+       struct sx_port *port = tty->driver_data;
 
        func_enter2();
        /* Always unthrottle even if flow control is not enabled on
@@ -2354,6 +2350,10 @@ static const struct tty_operations sx_ops = {
        .tiocmset = sx_tiocmset,
 };
 
+static const struct tty_port_operations sx_port_ops = {
+       .carrier_raised = sx_carrier_raised,
+};
+
 static int sx_init_drivers(void)
 {
        int error;
@@ -2410,6 +2410,7 @@ static int sx_init_portstructs(int nboards, int nports)
                for (j = 0; j < boards[i].nports; j++) {
                        sx_dprintk(SX_DEBUG_INIT, "initing port %d\n", j);
                        tty_port_init(&port->gs.port);
+                       port->gs.port.ops = &sx_port_ops;
                        port->gs.magic = SX_MAGIC;
                        port->gs.close_delay = HZ / 2;
                        port->gs.closing_wait = 30 * HZ;
index 500f5176b6ba801c3daa81f4d878dadf4a9b418e..b8063d4cad32ce9c122b051f9560656046864205 100644 (file)
@@ -977,7 +977,7 @@ static void ldisc_receive_buf(struct tty_struct *tty,
  */
 static void mgsl_stop(struct tty_struct *tty)
 {
-       struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;
+       struct mgsl_struct *info = tty->driver_data;
        unsigned long flags;
        
        if (mgsl_paranoia_check(info, tty->name, "mgsl_stop"))
@@ -1000,7 +1000,7 @@ static void mgsl_stop(struct tty_struct *tty)
  */
 static void mgsl_start(struct tty_struct *tty)
 {
-       struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;
+       struct mgsl_struct *info = tty->driver_data;
        unsigned long flags;
        
        if (mgsl_paranoia_check(info, tty->name, "mgsl_start"))
@@ -2057,7 +2057,7 @@ static int mgsl_put_char(struct tty_struct *tty, unsigned char ch)
  */
 static void mgsl_flush_chars(struct tty_struct *tty)
 {
-       struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;
+       struct mgsl_struct *info = tty->driver_data;
        unsigned long flags;
                                
        if ( debug_level >= DEBUG_LEVEL_INFO )
@@ -2109,7 +2109,7 @@ static int mgsl_write(struct tty_struct * tty,
                    const unsigned char *buf, int count)
 {
        int     c, ret = 0;
-       struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;
+       struct mgsl_struct *info = tty->driver_data;
        unsigned long flags;
        
        if ( debug_level >= DEBUG_LEVEL_INFO )
@@ -2232,7 +2232,7 @@ cleanup:
  */
 static int mgsl_write_room(struct tty_struct *tty)
 {
-       struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;
+       struct mgsl_struct *info = tty->driver_data;
        int     ret;
                                
        if (mgsl_paranoia_check(info, tty->name, "mgsl_write_room"))
@@ -2267,7 +2267,7 @@ static int mgsl_write_room(struct tty_struct *tty)
  */
 static int mgsl_chars_in_buffer(struct tty_struct *tty)
 {
-       struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;
+       struct mgsl_struct *info = tty->driver_data;
                         
        if (debug_level >= DEBUG_LEVEL_INFO)
                printk("%s(%d):mgsl_chars_in_buffer(%s)\n",
@@ -2301,7 +2301,7 @@ static int mgsl_chars_in_buffer(struct tty_struct *tty)
  */
 static void mgsl_flush_buffer(struct tty_struct *tty)
 {
-       struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;
+       struct mgsl_struct *info = tty->driver_data;
        unsigned long flags;
        
        if (debug_level >= DEBUG_LEVEL_INFO)
@@ -2329,7 +2329,7 @@ static void mgsl_flush_buffer(struct tty_struct *tty)
  */
 static void mgsl_send_xchar(struct tty_struct *tty, char ch)
 {
-       struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;
+       struct mgsl_struct *info = tty->driver_data;
        unsigned long flags;
 
        if (debug_level >= DEBUG_LEVEL_INFO)
@@ -2358,7 +2358,7 @@ static void mgsl_send_xchar(struct tty_struct *tty, char ch)
  */
 static void mgsl_throttle(struct tty_struct * tty)
 {
-       struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;
+       struct mgsl_struct *info = tty->driver_data;
        unsigned long flags;
        
        if (debug_level >= DEBUG_LEVEL_INFO)
@@ -2388,7 +2388,7 @@ static void mgsl_throttle(struct tty_struct * tty)
  */
 static void mgsl_unthrottle(struct tty_struct * tty)
 {
-       struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;
+       struct mgsl_struct *info = tty->driver_data;
        unsigned long flags;
        
        if (debug_level >= DEBUG_LEVEL_INFO)
@@ -2841,7 +2841,7 @@ static int modem_input_wait(struct mgsl_struct *info,int arg)
  */
 static int tiocmget(struct tty_struct *tty, struct file *file)
 {
-       struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;
+       struct mgsl_struct *info = tty->driver_data;
        unsigned int result;
        unsigned long flags;
 
@@ -2867,7 +2867,7 @@ static int tiocmget(struct tty_struct *tty, struct file *file)
 static int tiocmset(struct tty_struct *tty, struct file *file,
                    unsigned int set, unsigned int clear)
 {
-       struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;
+       struct mgsl_struct *info = tty->driver_data;
        unsigned long flags;
 
        if (debug_level >= DEBUG_LEVEL_INFO)
@@ -2898,7 +2898,7 @@ static int tiocmset(struct tty_struct *tty, struct file *file,
  */
 static int mgsl_break(struct tty_struct *tty, int break_state)
 {
-       struct mgsl_struct * info = (struct mgsl_struct *)tty->driver_data;
+       struct mgsl_struct * info = tty->driver_data;
        unsigned long flags;
        
        if (debug_level >= DEBUG_LEVEL_INFO)
@@ -2932,7 +2932,7 @@ static int mgsl_break(struct tty_struct *tty, int break_state)
 static int mgsl_ioctl(struct tty_struct *tty, struct file * file,
                    unsigned int cmd, unsigned long arg)
 {
-       struct mgsl_struct * info = (struct mgsl_struct *)tty->driver_data;
+       struct mgsl_struct * info = tty->driver_data;
        int ret;
        
        if (debug_level >= DEBUG_LEVEL_INFO)
@@ -3042,7 +3042,7 @@ static int mgsl_ioctl_common(struct mgsl_struct *info, unsigned int cmd, unsigne
  */
 static void mgsl_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
 {
-       struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;
+       struct mgsl_struct *info = tty->driver_data;
        unsigned long flags;
        
        if (debug_level >= DEBUG_LEVEL_INFO)
@@ -3096,7 +3096,7 @@ static void mgsl_set_termios(struct tty_struct *tty, struct ktermios *old_termio
  */
 static void mgsl_close(struct tty_struct *tty, struct file * filp)
 {
-       struct mgsl_struct * info = (struct mgsl_struct *)tty->driver_data;
+       struct mgsl_struct * info = tty->driver_data;
 
        if (mgsl_paranoia_check(info, tty->name, "mgsl_close"))
                return;
@@ -3104,70 +3104,18 @@ static void mgsl_close(struct tty_struct *tty, struct file * filp)
        if (debug_level >= DEBUG_LEVEL_INFO)
                printk("%s(%d):mgsl_close(%s) entry, count=%d\n",
                         __FILE__,__LINE__, info->device_name, info->port.count);
-                        
-       if (!info->port.count)
-               return;
 
-       if (tty_hung_up_p(filp))
+       if (tty_port_close_start(&info->port, tty, filp) == 0)                   
                goto cleanup;
                        
-       if ((tty->count == 1) && (info->port.count != 1)) {
-               /*
-                * tty->count is 1 and the tty structure will be freed.
-                * info->port.count should be one in this case.
-                * if it's not, correct it so that the port is shutdown.
-                */
-               printk("mgsl_close: bad refcount; tty->count is 1, "
-                      "info->port.count is %d\n", info->port.count);
-               info->port.count = 1;
-       }
-       
-       info->port.count--;
-       
-       /* if at least one open remaining, leave hardware active */
-       if (info->port.count)
-               goto cleanup;
-       
-       info->port.flags |= ASYNC_CLOSING;
-       
-       /* set tty->closing to notify line discipline to 
-        * only process XON/XOFF characters. Only the N_TTY
-        * discipline appears to use this (ppp does not).
-        */
-       tty->closing = 1;
-       
-       /* wait for transmit data to clear all layers */
-       
-       if (info->port.closing_wait != ASYNC_CLOSING_WAIT_NONE) {
-               if (debug_level >= DEBUG_LEVEL_INFO)
-                       printk("%s(%d):mgsl_close(%s) calling tty_wait_until_sent\n",
-                                __FILE__,__LINE__, info->device_name );
-               tty_wait_until_sent(tty, info->port.closing_wait);
-       }
-               
        if (info->port.flags & ASYNC_INITIALIZED)
                mgsl_wait_until_sent(tty, info->timeout);
-
        mgsl_flush_buffer(tty);
-
        tty_ldisc_flush(tty);
-               
        shutdown(info);
-       
-       tty->closing = 0;
+
+       tty_port_close_end(&info->port, tty);   
        info->port.tty = NULL;
-       
-       if (info->port.blocked_open) {
-               if (info->port.close_delay) {
-                       msleep_interruptible(jiffies_to_msecs(info->port.close_delay));
-               }
-               wake_up_interruptible(&info->port.open_wait);
-       }
-       
-       info->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
-                        
-       wake_up_interruptible(&info->port.close_wait);
-       
 cleanup:                       
        if (debug_level >= DEBUG_LEVEL_INFO)
                printk("%s(%d):mgsl_close(%s) exit, count=%d\n", __FILE__,__LINE__,
@@ -3188,7 +3136,7 @@ cleanup:
  */
 static void mgsl_wait_until_sent(struct tty_struct *tty, int timeout)
 {
-       struct mgsl_struct * info = (struct mgsl_struct *)tty->driver_data;
+       struct mgsl_struct * info = tty->driver_data;
        unsigned long orig_jiffies, char_time;
 
        if (!info )
@@ -3261,7 +3209,7 @@ exit:
  */
 static void mgsl_hangup(struct tty_struct *tty)
 {
-       struct mgsl_struct * info = (struct mgsl_struct *)tty->driver_data;
+       struct mgsl_struct * info = tty->driver_data;
        
        if (debug_level >= DEBUG_LEVEL_INFO)
                printk("%s(%d):mgsl_hangup(%s)\n",
@@ -3281,6 +3229,35 @@ static void mgsl_hangup(struct tty_struct *tty)
        
 }      /* end of mgsl_hangup() */
 
+/*
+ * carrier_raised()
+ *
+ *     Return true if carrier is raised
+ */
+
+static int carrier_raised(struct tty_port *port)
+{
+       unsigned long flags;
+       struct mgsl_struct *info = container_of(port, struct mgsl_struct, port);
+       
+       spin_lock_irqsave(&info->irq_spinlock, flags);
+       usc_get_serial_signals(info);
+       spin_unlock_irqrestore(&info->irq_spinlock, flags);
+       return (info->serial_signals & SerialSignal_DCD) ? 1 : 0;
+}
+
+static void raise_dtr_rts(struct tty_port *port)
+{
+       struct mgsl_struct *info = container_of(port, struct mgsl_struct, port);
+       unsigned long flags;
+
+       spin_lock_irqsave(&info->irq_spinlock,flags);
+       info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
+       usc_set_serial_signals(info);
+       spin_unlock_irqrestore(&info->irq_spinlock,flags);
+}
+
+
 /* block_til_ready()
  * 
  *     Block the current process until the specified port
@@ -3302,6 +3279,8 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
        bool            do_clocal = false;
        bool            extra_count = false;
        unsigned long   flags;
+       int             dcd;
+       struct tty_port *port = &info->port;
        
        if (debug_level >= DEBUG_LEVEL_INFO)
                printk("%s(%d):block_til_ready on %s\n",
@@ -3309,7 +3288,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
 
        if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){
                /* nonblock mode is set or port is not enabled */
-               info->port.flags |= ASYNC_NORMAL_ACTIVE;
+               port->flags |= ASYNC_NORMAL_ACTIVE;
                return 0;
        }
 
@@ -3318,50 +3297,42 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
 
        /* Wait for carrier detect and the line to become
         * free (i.e., not in use by the callout).  While we are in
-        * this loop, info->port.count is dropped by one, so that
+        * this loop, port->count is dropped by one, so that
         * mgsl_close() knows when to free things.  We restore it upon
         * exit, either normal or abnormal.
         */
         
        retval = 0;
-       add_wait_queue(&info->port.open_wait, &wait);
+       add_wait_queue(&port->open_wait, &wait);
        
        if (debug_level >= DEBUG_LEVEL_INFO)
                printk("%s(%d):block_til_ready before block on %s count=%d\n",
-                        __FILE__,__LINE__, tty->driver->name, info->port.count );
+                        __FILE__,__LINE__, tty->driver->name, port->count );
 
        spin_lock_irqsave(&info->irq_spinlock, flags);
        if (!tty_hung_up_p(filp)) {
                extra_count = true;
-               info->port.count--;
+               port->count--;
        }
        spin_unlock_irqrestore(&info->irq_spinlock, flags);
-       info->port.blocked_open++;
+       port->blocked_open++;
        
        while (1) {
-               if (tty->termios->c_cflag & CBAUD) {
-                       spin_lock_irqsave(&info->irq_spinlock,flags);
-                       info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
-                       usc_set_serial_signals(info);
-                       spin_unlock_irqrestore(&info->irq_spinlock,flags);
-               }
+               if (tty->termios->c_cflag & CBAUD)
+                       tty_port_raise_dtr_rts(port);
                
                set_current_state(TASK_INTERRUPTIBLE);
                
-               if (tty_hung_up_p(filp) || !(info->port.flags & ASYNC_INITIALIZED)){
-                       retval = (info->port.flags & ASYNC_HUP_NOTIFY) ?
+               if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)){
+                       retval = (port->flags & ASYNC_HUP_NOTIFY) ?
                                        -EAGAIN : -ERESTARTSYS;
                        break;
                }
                
-               spin_lock_irqsave(&info->irq_spinlock,flags);
-               usc_get_serial_signals(info);
-               spin_unlock_irqrestore(&info->irq_spinlock,flags);
+               dcd = tty_port_carrier_raised(&info->port);
                
-               if (!(info->port.flags & ASYNC_CLOSING) &&
-                   (do_clocal || (info->serial_signals & SerialSignal_DCD)) ) {
+               if (!(port->flags & ASYNC_CLOSING) && (do_clocal || dcd))
                        break;
-               }
                        
                if (signal_pending(current)) {
                        retval = -ERESTARTSYS;
@@ -3370,24 +3341,25 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
                
                if (debug_level >= DEBUG_LEVEL_INFO)
                        printk("%s(%d):block_til_ready blocking on %s count=%d\n",
-                                __FILE__,__LINE__, tty->driver->name, info->port.count );
+                                __FILE__,__LINE__, tty->driver->name, port->count );
                                 
                schedule();
        }
        
        set_current_state(TASK_RUNNING);
-       remove_wait_queue(&info->port.open_wait, &wait);
+       remove_wait_queue(&port->open_wait, &wait);
        
+       /* FIXME: Racy on hangup during close wait */
        if (extra_count)
-               info->port.count++;
-       info->port.blocked_open--;
+               port->count++;
+       port->blocked_open--;
        
        if (debug_level >= DEBUG_LEVEL_INFO)
                printk("%s(%d):block_til_ready after blocking on %s count=%d\n",
-                        __FILE__,__LINE__, tty->driver->name, info->port.count );
+                        __FILE__,__LINE__, tty->driver->name, port->count );
                         
        if (!retval)
-               info->port.flags |= ASYNC_NORMAL_ACTIVE;
+               port->flags |= ASYNC_NORMAL_ACTIVE;
                
        return retval;
        
@@ -4304,6 +4276,12 @@ static void mgsl_add_device( struct mgsl_struct *info )
 
 }      /* end of mgsl_add_device() */
 
+static const struct tty_port_operations mgsl_port_ops = {
+       .carrier_raised = carrier_raised,
+       .raise_dtr_rts = raise_dtr_rts,
+};
+
+
 /* mgsl_allocate_device()
  * 
  *     Allocate and initialize a device instance structure
@@ -4322,6 +4300,7 @@ static struct mgsl_struct* mgsl_allocate_device(void)
                printk("Error can't allocate device instance data\n");
        } else {
                tty_port_init(&info->port);
+               info->port.ops = &mgsl_port_ops;
                info->magic = MGSL_MAGIC;
                INIT_WORK(&info->task, mgsl_bh_handler);
                info->max_frame_size = 4096;
index 08911ed6649470d24e840d781e7bc2366bcd2dd6..53544e21f191a7d0779bbded3287040663ac209d 100644 (file)
@@ -720,44 +720,9 @@ static void close(struct tty_struct *tty, struct file *filp)
                return;
        DBGINFO(("%s close entry, count=%d\n", info->device_name, info->port.count));
 
-       if (!info->port.count)
-               return;
-
-       if (tty_hung_up_p(filp))
-               goto cleanup;
-
-       if ((tty->count == 1) && (info->port.count != 1)) {
-               /*
-                * tty->count is 1 and the tty structure will be freed.
-                * info->port.count should be one in this case.
-                * if it's not, correct it so that the port is shutdown.
-                */
-               DBGERR(("%s close: bad refcount; tty->count=1, "
-                      "info->port.count=%d\n", info->device_name, info->port.count));
-               info->port.count = 1;
-       }
-
-       info->port.count--;
-
-       /* if at least one open remaining, leave hardware active */
-       if (info->port.count)
+       if (tty_port_close_start(&info->port, tty, filp) == 0)
                goto cleanup;
 
-       info->port.flags |= ASYNC_CLOSING;
-
-       /* set tty->closing to notify line discipline to
-        * only process XON/XOFF characters. Only the N_TTY
-        * discipline appears to use this (ppp does not).
-        */
-       tty->closing = 1;
-
-       /* wait for transmit data to clear all layers */
-
-       if (info->port.closing_wait != ASYNC_CLOSING_WAIT_NONE) {
-               DBGINFO(("%s call tty_wait_until_sent\n", info->device_name));
-               tty_wait_until_sent(tty, info->port.closing_wait);
-       }
-
        if (info->port.flags & ASYNC_INITIALIZED)
                wait_until_sent(tty, info->timeout);
        flush_buffer(tty);
@@ -765,20 +730,8 @@ static void close(struct tty_struct *tty, struct file *filp)
 
        shutdown(info);
 
-       tty->closing = 0;
+       tty_port_close_end(&info->port, tty);
        info->port.tty = NULL;
-
-       if (info->port.blocked_open) {
-               if (info->port.close_delay) {
-                       msleep_interruptible(jiffies_to_msecs(info->port.close_delay));
-               }
-               wake_up_interruptible(&info->port.open_wait);
-       }
-
-       info->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
-
-       wake_up_interruptible(&info->port.close_wait);
-
 cleanup:
        DBGINFO(("%s close exit, count=%d\n", tty->driver->name, info->port.count));
 }
@@ -3132,6 +3085,29 @@ static int tiocmset(struct tty_struct *tty, struct file *file,
        return 0;
 }
 
+static int carrier_raised(struct tty_port *port)
+{
+       unsigned long flags;
+       struct slgt_info *info = container_of(port, struct slgt_info, port);
+
+       spin_lock_irqsave(&info->lock,flags);
+       get_signals(info);
+       spin_unlock_irqrestore(&info->lock,flags);
+       return (info->signals & SerialSignal_DCD) ? 1 : 0;
+}
+
+static void raise_dtr_rts(struct tty_port *port)
+{
+       unsigned long flags;
+       struct slgt_info *info = container_of(port, struct slgt_info, port);
+
+       spin_lock_irqsave(&info->lock,flags);
+       info->signals |= SerialSignal_RTS + SerialSignal_DTR;
+       set_signals(info);
+       spin_unlock_irqrestore(&info->lock,flags);
+}
+
+
 /*
  *  block current process until the device is ready to open
  */
@@ -3143,12 +3119,14 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
        bool            do_clocal = false;
        bool            extra_count = false;
        unsigned long   flags;
+       int             cd;
+       struct tty_port *port = &info->port;
 
        DBGINFO(("%s block_til_ready\n", tty->driver->name));
 
        if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){
                /* nonblock mode is set or port is not enabled */
-               info->port.flags |= ASYNC_NORMAL_ACTIVE;
+               port->flags |= ASYNC_NORMAL_ACTIVE;
                return 0;
        }
 
@@ -3157,46 +3135,38 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
 
        /* Wait for carrier detect and the line to become
         * free (i.e., not in use by the callout).  While we are in
-        * this loop, info->port.count is dropped by one, so that
+        * this loop, port->count is dropped by one, so that
         * close() knows when to free things.  We restore it upon
         * exit, either normal or abnormal.
         */
 
        retval = 0;
-       add_wait_queue(&info->port.open_wait, &wait);
+       add_wait_queue(&port->open_wait, &wait);
 
        spin_lock_irqsave(&info->lock, flags);
        if (!tty_hung_up_p(filp)) {
                extra_count = true;
-               info->port.count--;
+               port->count--;
        }
        spin_unlock_irqrestore(&info->lock, flags);
-       info->port.blocked_open++;
+       port->blocked_open++;
 
        while (1) {
-               if ((tty->termios->c_cflag & CBAUD)) {
-                       spin_lock_irqsave(&info->lock,flags);
-                       info->signals |= SerialSignal_RTS + SerialSignal_DTR;
-                       set_signals(info);
-                       spin_unlock_irqrestore(&info->lock,flags);
-               }
+               if ((tty->termios->c_cflag & CBAUD))
+                       tty_port_raise_dtr_rts(port);
 
                set_current_state(TASK_INTERRUPTIBLE);
 
-               if (tty_hung_up_p(filp) || !(info->port.flags & ASYNC_INITIALIZED)){
-                       retval = (info->port.flags & ASYNC_HUP_NOTIFY) ?
+               if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)){
+                       retval = (port->flags & ASYNC_HUP_NOTIFY) ?
                                        -EAGAIN : -ERESTARTSYS;
                        break;
                }
 
-               spin_lock_irqsave(&info->lock,flags);
-               get_signals(info);
-               spin_unlock_irqrestore(&info->lock,flags);
+               cd = tty_port_carrier_raised(port);
 
-               if (!(info->port.flags & ASYNC_CLOSING) &&
-                   (do_clocal || (info->signals & SerialSignal_DCD)) ) {
+               if (!(port->flags & ASYNC_CLOSING) && (do_clocal || cd ))
                        break;
-               }
 
                if (signal_pending(current)) {
                        retval = -ERESTARTSYS;
@@ -3208,14 +3178,14 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
        }
 
        set_current_state(TASK_RUNNING);
-       remove_wait_queue(&info->port.open_wait, &wait);
+       remove_wait_queue(&port->open_wait, &wait);
 
        if (extra_count)
-               info->port.count++;
-       info->port.blocked_open--;
+               port->count++;
+       port->blocked_open--;
 
        if (!retval)
-               info->port.flags |= ASYNC_NORMAL_ACTIVE;
+               port->flags |= ASYNC_NORMAL_ACTIVE;
 
        DBGINFO(("%s block_til_ready ready, rc=%d\n", tty->driver->name, retval));
        return retval;
@@ -3444,6 +3414,11 @@ static void add_device(struct slgt_info *info)
 #endif
 }
 
+static const struct tty_port_operations slgt_port_ops = {
+       .carrier_raised = carrier_raised,
+       .raise_dtr_rts = raise_dtr_rts,
+};
+
 /*
  *  allocate device instance structure, return NULL on failure
  */
@@ -3458,6 +3433,7 @@ static struct slgt_info *alloc_dev(int adapter_num, int port_num, struct pci_dev
                        driver_name, adapter_num, port_num));
        } else {
                tty_port_init(&info->port);
+               info->port.ops = &slgt_port_ops;
                info->magic = MGSL_MAGIC;
                INIT_WORK(&info->task, bh_handler);
                info->max_frame_size = 4096;
index 6bdb44f7bec2804d1288b20e7b1b66e915ee81ed..7b0c5b2dd2635cbefbb9a919158aba8d5cef9a0b 100644 (file)
@@ -558,6 +558,7 @@ static void release_resources(SLMP_INFO *info);
 
 static int  startup(SLMP_INFO *info);
 static int  block_til_ready(struct tty_struct *tty, struct file * filp,SLMP_INFO *info);
+static int carrier_raised(struct tty_port *port);
 static void shutdown(SLMP_INFO *info);
 static void program_hw(SLMP_INFO *info);
 static void change_params(SLMP_INFO *info);
@@ -800,7 +801,7 @@ cleanup:
  */
 static void close(struct tty_struct *tty, struct file *filp)
 {
-       SLMP_INFO * info = (SLMP_INFO *)tty->driver_data;
+       SLMP_INFO * info = tty->driver_data;
 
        if (sanity_check(info, tty->name, "close"))
                return;
@@ -809,70 +810,18 @@ static void close(struct tty_struct *tty, struct file *filp)
                printk("%s(%d):%s close() entry, count=%d\n",
                         __FILE__,__LINE__, info->device_name, info->port.count);
 
-       if (!info->port.count)
-               return;
-
-       if (tty_hung_up_p(filp))
-               goto cleanup;
-
-       if ((tty->count == 1) && (info->port.count != 1)) {
-               /*
-                * tty->count is 1 and the tty structure will be freed.
-                * info->port.count should be one in this case.
-                * if it's not, correct it so that the port is shutdown.
-                */
-               printk("%s(%d):%s close: bad refcount; tty->count is 1, "
-                      "info->port.count is %d\n",
-                        __FILE__,__LINE__, info->device_name, info->port.count);
-               info->port.count = 1;
-       }
-
-       info->port.count--;
-
-       /* if at least one open remaining, leave hardware active */
-       if (info->port.count)
+       if (tty_port_close_start(&info->port, tty, filp) == 0)
                goto cleanup;
-
-       info->port.flags |= ASYNC_CLOSING;
-
-       /* set tty->closing to notify line discipline to
-        * only process XON/XOFF characters. Only the N_TTY
-        * discipline appears to use this (ppp does not).
-        */
-       tty->closing = 1;
-
-       /* wait for transmit data to clear all layers */
-
-       if (info->port.closing_wait != ASYNC_CLOSING_WAIT_NONE) {
-               if (debug_level >= DEBUG_LEVEL_INFO)
-                       printk("%s(%d):%s close() calling tty_wait_until_sent\n",
-                                __FILE__,__LINE__, info->device_name );
-               tty_wait_until_sent(tty, info->port.closing_wait);
-       }
-
+               
        if (info->port.flags & ASYNC_INITIALIZED)
                wait_until_sent(tty, info->timeout);
 
        flush_buffer(tty);
-
        tty_ldisc_flush(tty);
-
        shutdown(info);
 
-       tty->closing = 0;
+       tty_port_close_end(&info->port, tty);
        info->port.tty = NULL;
-
-       if (info->port.blocked_open) {
-               if (info->port.close_delay) {
-                       msleep_interruptible(jiffies_to_msecs(info->port.close_delay));
-               }
-               wake_up_interruptible(&info->port.open_wait);
-       }
-
-       info->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
-
-       wake_up_interruptible(&info->port.close_wait);
-
 cleanup:
        if (debug_level >= DEBUG_LEVEL_INFO)
                printk("%s(%d):%s close() exit, count=%d\n", __FILE__,__LINE__,
@@ -884,7 +833,7 @@ cleanup:
  */
 static void hangup(struct tty_struct *tty)
 {
-       SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
+       SLMP_INFO *info = tty->driver_data;
 
        if (debug_level >= DEBUG_LEVEL_INFO)
                printk("%s(%d):%s hangup()\n",
@@ -907,7 +856,7 @@ static void hangup(struct tty_struct *tty)
  */
 static void set_termios(struct tty_struct *tty, struct ktermios *old_termios)
 {
-       SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
+       SLMP_INFO *info = tty->driver_data;
        unsigned long flags;
 
        if (debug_level >= DEBUG_LEVEL_INFO)
@@ -960,7 +909,7 @@ static int write(struct tty_struct *tty,
                 const unsigned char *buf, int count)
 {
        int     c, ret = 0;
-       SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
+       SLMP_INFO *info = tty->driver_data;
        unsigned long flags;
 
        if (debug_level >= DEBUG_LEVEL_INFO)
@@ -1038,7 +987,7 @@ cleanup:
  */
 static int put_char(struct tty_struct *tty, unsigned char ch)
 {
-       SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
+       SLMP_INFO *info = tty->driver_data;
        unsigned long flags;
        int ret = 0;
 
@@ -1075,7 +1024,7 @@ static int put_char(struct tty_struct *tty, unsigned char ch)
  */
 static void send_xchar(struct tty_struct *tty, char ch)
 {
-       SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
+       SLMP_INFO *info = tty->driver_data;
        unsigned long flags;
 
        if (debug_level >= DEBUG_LEVEL_INFO)
@@ -1099,7 +1048,7 @@ static void send_xchar(struct tty_struct *tty, char ch)
  */
 static void wait_until_sent(struct tty_struct *tty, int timeout)
 {
-       SLMP_INFO * info = (SLMP_INFO *)tty->driver_data;
+       SLMP_INFO * info = tty->driver_data;
        unsigned long orig_jiffies, char_time;
 
        if (!info )
@@ -1166,7 +1115,7 @@ exit:
  */
 static int write_room(struct tty_struct *tty)
 {
-       SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
+       SLMP_INFO *info = tty->driver_data;
        int ret;
 
        if (sanity_check(info, tty->name, "write_room"))
@@ -1193,7 +1142,7 @@ static int write_room(struct tty_struct *tty)
  */
 static void flush_chars(struct tty_struct *tty)
 {
-       SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
+       SLMP_INFO *info = tty->driver_data;
        unsigned long flags;
 
        if ( debug_level >= DEBUG_LEVEL_INFO )
@@ -1232,7 +1181,7 @@ static void flush_chars(struct tty_struct *tty)
  */
 static void flush_buffer(struct tty_struct *tty)
 {
-       SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
+       SLMP_INFO *info = tty->driver_data;
        unsigned long flags;
 
        if (debug_level >= DEBUG_LEVEL_INFO)
@@ -1254,7 +1203,7 @@ static void flush_buffer(struct tty_struct *tty)
  */
 static void tx_hold(struct tty_struct *tty)
 {
-       SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
+       SLMP_INFO *info = tty->driver_data;
        unsigned long flags;
 
        if (sanity_check(info, tty->name, "tx_hold"))
@@ -1274,7 +1223,7 @@ static void tx_hold(struct tty_struct *tty)
  */
 static void tx_release(struct tty_struct *tty)
 {
-       SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
+       SLMP_INFO *info = tty->driver_data;
        unsigned long flags;
 
        if (sanity_check(info, tty->name, "tx_release"))
@@ -1304,7 +1253,7 @@ static void tx_release(struct tty_struct *tty)
 static int do_ioctl(struct tty_struct *tty, struct file *file,
                 unsigned int cmd, unsigned long arg)
 {
-       SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
+       SLMP_INFO *info = tty->driver_data;
        int error;
        struct mgsl_icount cnow;        /* kernel counter temps */
        struct serial_icounter_struct __user *p_cuser;  /* user space */
@@ -1515,7 +1464,7 @@ done:
  */
 static int chars_in_buffer(struct tty_struct *tty)
 {
-       SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
+       SLMP_INFO *info = tty->driver_data;
 
        if (sanity_check(info, tty->name, "chars_in_buffer"))
                return 0;
@@ -1531,7 +1480,7 @@ static int chars_in_buffer(struct tty_struct *tty)
  */
 static void throttle(struct tty_struct * tty)
 {
-       SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
+       SLMP_INFO *info = tty->driver_data;
        unsigned long flags;
 
        if (debug_level >= DEBUG_LEVEL_INFO)
@@ -1556,7 +1505,7 @@ static void throttle(struct tty_struct * tty)
  */
 static void unthrottle(struct tty_struct * tty)
 {
-       SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
+       SLMP_INFO *info = tty->driver_data;
        unsigned long flags;
 
        if (debug_level >= DEBUG_LEVEL_INFO)
@@ -1587,7 +1536,7 @@ static void unthrottle(struct tty_struct * tty)
 static int set_break(struct tty_struct *tty, int break_state)
 {
        unsigned char RegValue;
-       SLMP_INFO * info = (SLMP_INFO *)tty->driver_data;
+       SLMP_INFO * info = tty->driver_data;
        unsigned long flags;
 
        if (debug_level >= DEBUG_LEVEL_INFO)
@@ -3269,7 +3218,7 @@ static int modem_input_wait(SLMP_INFO *info,int arg)
  */
 static int tiocmget(struct tty_struct *tty, struct file *file)
 {
-       SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
+       SLMP_INFO *info = tty->driver_data;
        unsigned int result;
        unsigned long flags;
 
@@ -3295,7 +3244,7 @@ static int tiocmget(struct tty_struct *tty, struct file *file)
 static int tiocmset(struct tty_struct *tty, struct file *file,
                    unsigned int set, unsigned int clear)
 {
-       SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
+       SLMP_INFO *info = tty->driver_data;
        unsigned long flags;
 
        if (debug_level >= DEBUG_LEVEL_INFO)
@@ -3318,7 +3267,28 @@ static int tiocmset(struct tty_struct *tty, struct file *file,
        return 0;
 }
 
+static int carrier_raised(struct tty_port *port)
+{
+       SLMP_INFO *info = container_of(port, SLMP_INFO, port);
+       unsigned long flags;
+
+       spin_lock_irqsave(&info->lock,flags);
+       get_signals(info);
+       spin_unlock_irqrestore(&info->lock,flags);
 
+       return (info->serial_signals & SerialSignal_DCD) ? 1 : 0;
+}
+
+static void raise_dtr_rts(struct tty_port *port)
+{
+       SLMP_INFO *info = container_of(port, SLMP_INFO, port);
+       unsigned long flags;
+
+       spin_lock_irqsave(&info->lock,flags);
+       info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
+       set_signals(info);
+       spin_unlock_irqrestore(&info->lock,flags);
+}
 
 /* Block the current process until the specified port is ready to open.
  */
@@ -3330,6 +3300,8 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
        bool            do_clocal = false;
        bool            extra_count = false;
        unsigned long   flags;
+       int             cd;
+       struct tty_port *port = &info->port;
 
        if (debug_level >= DEBUG_LEVEL_INFO)
                printk("%s(%d):%s block_til_ready()\n",
@@ -3338,7 +3310,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
        if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){
                /* nonblock mode is set or port is not enabled */
                /* just verify that callout device is not active */
-               info->port.flags |= ASYNC_NORMAL_ACTIVE;
+               port->flags |= ASYNC_NORMAL_ACTIVE;
                return 0;
        }
 
@@ -3347,50 +3319,42 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
 
        /* Wait for carrier detect and the line to become
         * free (i.e., not in use by the callout).  While we are in
-        * this loop, info->port.count is dropped by one, so that
+        * this loop, port->count is dropped by one, so that
         * close() knows when to free things.  We restore it upon
         * exit, either normal or abnormal.
         */
 
        retval = 0;
-       add_wait_queue(&info->port.open_wait, &wait);
+       add_wait_queue(&port->open_wait, &wait);
 
        if (debug_level >= DEBUG_LEVEL_INFO)
                printk("%s(%d):%s block_til_ready() before block, count=%d\n",
-                        __FILE__,__LINE__, tty->driver->name, info->port.count );
+                        __FILE__,__LINE__, tty->driver->name, port->count );
 
        spin_lock_irqsave(&info->lock, flags);
        if (!tty_hung_up_p(filp)) {
                extra_count = true;
-               info->port.count--;
+               port->count--;
        }
        spin_unlock_irqrestore(&info->lock, flags);
-       info->port.blocked_open++;
+       port->blocked_open++;
 
        while (1) {
-               if ((tty->termios->c_cflag & CBAUD)) {
-                       spin_lock_irqsave(&info->lock,flags);
-                       info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
-                       set_signals(info);
-                       spin_unlock_irqrestore(&info->lock,flags);
-               }
+               if (tty->termios->c_cflag & CBAUD)
+                       tty_port_raise_dtr_rts(port);
 
                set_current_state(TASK_INTERRUPTIBLE);
 
-               if (tty_hung_up_p(filp) || !(info->port.flags & ASYNC_INITIALIZED)){
-                       retval = (info->port.flags & ASYNC_HUP_NOTIFY) ?
+               if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)){
+                       retval = (port->flags & ASYNC_HUP_NOTIFY) ?
                                        -EAGAIN : -ERESTARTSYS;
                        break;
                }
 
-               spin_lock_irqsave(&info->lock,flags);
-               get_signals(info);
-               spin_unlock_irqrestore(&info->lock,flags);
+               cd = tty_port_carrier_raised(port);
 
-               if (!(info->port.flags & ASYNC_CLOSING) &&
-                   (do_clocal || (info->serial_signals & SerialSignal_DCD)) ) {
+               if (!(port->flags & ASYNC_CLOSING) && (do_clocal || cd))
                        break;
-               }
 
                if (signal_pending(current)) {
                        retval = -ERESTARTSYS;
@@ -3399,24 +3363,24 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
 
                if (debug_level >= DEBUG_LEVEL_INFO)
                        printk("%s(%d):%s block_til_ready() count=%d\n",
-                                __FILE__,__LINE__, tty->driver->name, info->port.count );
+                                __FILE__,__LINE__, tty->driver->name, port->count );
 
                schedule();
        }
 
        set_current_state(TASK_RUNNING);
-       remove_wait_queue(&info->port.open_wait, &wait);
+       remove_wait_queue(&port->open_wait, &wait);
 
        if (extra_count)
-               info->port.count++;
-       info->port.blocked_open--;
+               port->count++;
+       port->blocked_open--;
 
        if (debug_level >= DEBUG_LEVEL_INFO)
                printk("%s(%d):%s block_til_ready() after, count=%d\n",
-                        __FILE__,__LINE__, tty->driver->name, info->port.count );
+                        __FILE__,__LINE__, tty->driver->name, port->count );
 
        if (!retval)
-               info->port.flags |= ASYNC_NORMAL_ACTIVE;
+               port->flags |= ASYNC_NORMAL_ACTIVE;
 
        return retval;
 }
@@ -3782,6 +3746,11 @@ static void add_device(SLMP_INFO *info)
 #endif
 }
 
+static const struct tty_port_operations port_ops = {
+       .carrier_raised = carrier_raised,
+       .raise_dtr_rts = raise_dtr_rts,
+};
+
 /* Allocate and initialize a device instance structure
  *
  * Return Value:       pointer to SLMP_INFO if success, otherwise NULL
@@ -3798,6 +3767,7 @@ static SLMP_INFO *alloc_dev(int adapter_num, int port_num, struct pci_dev *pdev)
                        __FILE__,__LINE__, adapter_num, port_num);
        } else {
                tty_port_init(&info->port);
+               info->port.ops = &port_ops;
                info->magic = MGSL_MAGIC;
                INIT_WORK(&info->task, bh_handler);
                info->max_frame_size = 4096;
@@ -3940,6 +3910,7 @@ static const struct tty_operations ops = {
        .tiocmset = tiocmset,
 };
 
+
 static void synclinkmp_cleanup(void)
 {
        int rc;
index db15f9ba7c0bd1324afdfdedb5bf1c5ba2948320..d33e5ab061779a67e63b305b30b29d01f6fe38ca 100644 (file)
@@ -1111,9 +1111,7 @@ void tty_write_message(struct tty_struct *tty, char *msg)
  *             Locks the line discipline as required
  *             Writes to the tty driver are serialized by the atomic_write_lock
  *     and are then processed in chunks to the device. The line discipline
- *     write method will not be involked in parallel for each device
- *             The line discipline write method is called under the big
- *     kernel lock for historical reasons. New code should not rely on this.
+ *     write method will not be invoked in parallel for each device.
  */
 
 static ssize_t tty_write(struct file *file, const char __user *buf,
@@ -1213,7 +1211,7 @@ static void tty_line_name(struct tty_driver *driver, int index, char *p)
  *     be held until the 'fast-open' is also done. Will change once we
  *     have refcounting in the driver and per driver locking
  */
-struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver,
+static struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver,
                struct inode *inode, int idx)
 {
        struct tty_struct *tty;
@@ -2050,7 +2048,6 @@ static int tiocgwinsz(struct tty_struct *tty, struct winsize __user *arg)
 /**
  *     tty_do_resize           -       resize event
  *     @tty: tty being resized
- *     @real_tty: real tty (not the same as tty if using a pty/tty pair)
  *     @rows: rows (character)
  *     @cols: cols (character)
  *
@@ -2058,41 +2055,34 @@ static int tiocgwinsz(struct tty_struct *tty, struct winsize __user *arg)
  *     peform a terminal resize correctly
  */
 
-int tty_do_resize(struct tty_struct *tty, struct tty_struct *real_tty,
-                                       struct winsize *ws)
+int tty_do_resize(struct tty_struct *tty, struct winsize *ws)
 {
-       struct pid *pgrp, *rpgrp;
+       struct pid *pgrp;
        unsigned long flags;
 
-       /* For a PTY we need to lock the tty side */
-       mutex_lock(&real_tty->termios_mutex);
-       if (!memcmp(ws, &real_tty->winsize, sizeof(*ws)))
+       /* Lock the tty */
+       mutex_lock(&tty->termios_mutex);
+       if (!memcmp(ws, &tty->winsize, sizeof(*ws)))
                goto done;
        /* Get the PID values and reference them so we can
           avoid holding the tty ctrl lock while sending signals */
        spin_lock_irqsave(&tty->ctrl_lock, flags);
        pgrp = get_pid(tty->pgrp);
-       rpgrp = get_pid(real_tty->pgrp);
        spin_unlock_irqrestore(&tty->ctrl_lock, flags);
 
        if (pgrp)
                kill_pgrp(pgrp, SIGWINCH, 1);
-       if (rpgrp != pgrp && rpgrp)
-               kill_pgrp(rpgrp, SIGWINCH, 1);
-
        put_pid(pgrp);
-       put_pid(rpgrp);
 
        tty->winsize = *ws;
-       real_tty->winsize = *ws;
 done:
-       mutex_unlock(&real_tty->termios_mutex);
+       mutex_unlock(&tty->termios_mutex);
        return 0;
 }
 
 /**
  *     tiocswinsz              -       implement window size set ioctl
- *     @tty; tty
+ *     @tty; tty side of tty
  *     @arg: user buffer for result
  *
  *     Copies the user idea of the window size to the kernel. Traditionally
@@ -2105,17 +2095,16 @@ done:
  *     then calls into the default method.
  */
 
-static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty,
-       struct winsize __user *arg)
+static int tiocswinsz(struct tty_struct *tty, struct winsize __user *arg)
 {
        struct winsize tmp_ws;
        if (copy_from_user(&tmp_ws, arg, sizeof(*arg)))
                return -EFAULT;
 
        if (tty->ops->resize)
-               return tty->ops->resize(tty, real_tty, &tmp_ws);
+               return tty->ops->resize(tty, &tmp_ws);
        else
-               return tty_do_resize(tty, real_tty, &tmp_ws);
+               return tty_do_resize(tty, &tmp_ws);
 }
 
 /**
@@ -2540,7 +2529,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        case TIOCGWINSZ:
                return tiocgwinsz(real_tty, p);
        case TIOCSWINSZ:
-               return tiocswinsz(tty, real_tty, p);
+               return tiocswinsz(real_tty, p);
        case TIOCCONS:
                return real_tty != tty ? -EINVAL : tioccons(file);
        case FIONBIO:
@@ -2785,6 +2774,8 @@ void initialize_tty_struct(struct tty_struct *tty,
        INIT_WORK(&tty->hangup_work, do_tty_hangup);
        mutex_init(&tty->atomic_read_lock);
        mutex_init(&tty->atomic_write_lock);
+       mutex_init(&tty->output_lock);
+       mutex_init(&tty->echo_lock);
        spin_lock_init(&tty->read_lock);
        spin_lock_init(&tty->ctrl_lock);
        INIT_LIST_HEAD(&tty->tty_files);
index f307f135cbfb63f23aebb9edc89eb7c559ed2fce..7a84b406a9522d633f6eab84ada8134319b2aeac 100644 (file)
@@ -316,8 +316,7 @@ struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty)
 {
        /* wait_event is a macro */
        wait_event(tty_ldisc_wait, tty_ldisc_try(tty));
-       if (tty->ldisc.refcount == 0)
-               printk(KERN_ERR "tty_ldisc_ref_wait\n");
+       WARN_ON(tty->ldisc.refcount == 0);
        return &tty->ldisc;
 }
 
@@ -376,15 +375,17 @@ EXPORT_SYMBOL_GPL(tty_ldisc_deref);
  *     @tty: terminal to activate ldisc on
  *
  *     Set the TTY_LDISC flag when the line discipline can be called
- *     again. Do necessary wakeups for existing sleepers.
+ *     again. Do necessary wakeups for existing sleepers. Clear the LDISC
+ *     changing flag to indicate any ldisc change is now over.
  *
- *     Note: nobody should set this bit except via this function. Clearing
- *     directly is allowed.
+ *     Note: nobody should set the TTY_LDISC bit except via this function.
+ *     Clearing directly is allowed.
  */
 
 void tty_ldisc_enable(struct tty_struct *tty)
 {
        set_bit(TTY_LDISC, &tty->flags);
+       clear_bit(TTY_LDISC_CHANGING, &tty->flags);
        wake_up(&tty_ldisc_wait);
 }
 
@@ -496,7 +497,14 @@ restart:
         *      reference to the line discipline. The TTY_LDISC bit
         *      prevents anyone taking a reference once it is clear.
         *      We need the lock to avoid racing reference takers.
+        *
+        *      We must clear the TTY_LDISC bit here to avoid a livelock
+        *      with a userspace app continually trying to use the tty in
+        *      parallel to the change and re-referencing the tty.
         */
+       clear_bit(TTY_LDISC, &tty->flags);
+       if (o_tty)
+               clear_bit(TTY_LDISC, &o_tty->flags);
 
        spin_lock_irqsave(&tty_ldisc_lock, flags);
        if (tty->ldisc.refcount || (o_tty && o_tty->ldisc.refcount)) {
@@ -528,7 +536,7 @@ restart:
         *      If the TTY_LDISC bit is set, then we are racing against
         *      another ldisc change
         */
-       if (!test_bit(TTY_LDISC, &tty->flags)) {
+       if (test_bit(TTY_LDISC_CHANGING, &tty->flags)) {
                struct tty_ldisc *ld;
                spin_unlock_irqrestore(&tty_ldisc_lock, flags);
                tty_ldisc_put(new_ldisc.ops);
@@ -536,10 +544,14 @@ restart:
                tty_ldisc_deref(ld);
                goto restart;
        }
-
-       clear_bit(TTY_LDISC, &tty->flags);
+       /*
+        *      This flag is used to avoid two parallel ldisc changes. Once
+        *      open and close are fine grained locked this may work better
+        *      as a mutex shared with the open/close/hup paths
+        */
+       set_bit(TTY_LDISC_CHANGING, &tty->flags);
        if (o_tty)
-               clear_bit(TTY_LDISC, &o_tty->flags);
+               set_bit(TTY_LDISC_CHANGING, &o_tty->flags);
        spin_unlock_irqrestore(&tty_ldisc_lock, flags);
        
        /*
index c8f8024cb40e5d6b4fcc6ad1a8f4408104e9f81a..9b8004c72686a45f6ea577f1cd342e001dbbfa49 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
+#include <linux/serial.h>
 #include <linux/timer.h>
 #include <linux/string.h>
 #include <linux/slab.h>
@@ -94,3 +95,227 @@ void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty)
        spin_unlock_irqrestore(&port->lock, flags);
 }
 EXPORT_SYMBOL(tty_port_tty_set);
+
+/**
+ *     tty_port_hangup         -       hangup helper
+ *     @port: tty port
+ *
+ *     Perform port level tty hangup flag and count changes. Drop the tty
+ *     reference.
+ */
+
+void tty_port_hangup(struct tty_port *port)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       port->count = 0;
+       port->flags &= ~ASYNC_NORMAL_ACTIVE;
+       if (port->tty)
+               tty_kref_put(port->tty);
+       port->tty = NULL;
+       spin_unlock_irqrestore(&port->lock, flags);
+       wake_up_interruptible(&port->open_wait);
+}
+EXPORT_SYMBOL(tty_port_hangup);
+
+/**
+ *     tty_port_carrier_raised -       carrier raised check
+ *     @port: tty port
+ *
+ *     Wrapper for the carrier detect logic. For the moment this is used
+ *     to hide some internal details. This will eventually become entirely
+ *     internal to the tty port.
+ */
+
+int tty_port_carrier_raised(struct tty_port *port)
+{
+       if (port->ops->carrier_raised == NULL)
+               return 1;
+       return port->ops->carrier_raised(port);
+}
+EXPORT_SYMBOL(tty_port_carrier_raised);
+
+/**
+ *     tty_port_raise_dtr_rts  -       Riase DTR/RTS
+ *     @port: tty port
+ *
+ *     Wrapper for the DTR/RTS raise logic. For the moment this is used
+ *     to hide some internal details. This will eventually become entirely
+ *     internal to the tty port.
+ */
+
+void tty_port_raise_dtr_rts(struct tty_port *port)
+{
+       if (port->ops->raise_dtr_rts)
+               port->ops->raise_dtr_rts(port);
+}
+EXPORT_SYMBOL(tty_port_raise_dtr_rts);
+
+/**
+ *     tty_port_block_til_ready        -       Waiting logic for tty open
+ *     @port: the tty port being opened
+ *     @tty: the tty device being bound
+ *     @filp: the file pointer of the opener
+ *
+ *     Implement the core POSIX/SuS tty behaviour when opening a tty device.
+ *     Handles:
+ *             - hangup (both before and during)
+ *             - non blocking open
+ *             - rts/dtr/dcd
+ *             - signals
+ *             - port flags and counts
+ *
+ *     The passed tty_port must implement the carrier_raised method if it can
+ *     do carrier detect and the raise_dtr_rts method if it supports software
+ *     management of these lines. Note that the dtr/rts raise is done each
+ *     iteration as a hangup may have previously dropped them while we wait.
+ */
+int tty_port_block_til_ready(struct tty_port *port,
+                               struct tty_struct *tty, struct file *filp)
+{
+       int do_clocal = 0, retval;
+       unsigned long flags;
+       DECLARE_WAITQUEUE(wait, current);
+       int cd;
+
+       /* block if port is in the process of being closed */
+       if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
+               interruptible_sleep_on(&port->close_wait);
+               if (port->flags & ASYNC_HUP_NOTIFY)
+                       return -EAGAIN;
+               else
+                       return -ERESTARTSYS;
+       }
+
+       /* if non-blocking mode is set we can pass directly to open unless
+          the port has just hung up or is in another error state */
+       if ((filp->f_flags & O_NONBLOCK) ||
+                       (tty->flags & (1 << TTY_IO_ERROR))) {
+               port->flags |= ASYNC_NORMAL_ACTIVE;
+               return 0;
+       }
+
+       if (C_CLOCAL(tty))
+               do_clocal = 1;
+
+       /* Block waiting until we can proceed. We may need to wait for the
+          carrier, but we must also wait for any close that is in progress
+          before the next open may complete */
+
+       retval = 0;
+       add_wait_queue(&port->open_wait, &wait);
+
+       /* The port lock protects the port counts */
+       spin_lock_irqsave(&port->lock, flags);
+       if (!tty_hung_up_p(filp))
+               port->count--;
+       port->blocked_open++;
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       while (1) {
+               /* Indicate we are open */
+               if (tty->termios->c_cflag & CBAUD)
+                       tty_port_raise_dtr_rts(port);
+
+               set_current_state(TASK_INTERRUPTIBLE);
+               /* Check for a hangup or uninitialised port. Return accordingly */
+               if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
+                       if (port->flags & ASYNC_HUP_NOTIFY)
+                               retval = -EAGAIN;
+                       else
+                               retval = -ERESTARTSYS;
+                       break;
+               }
+               /* Probe the carrier. For devices with no carrier detect this
+                  will always return true */
+               cd = tty_port_carrier_raised(port);
+               if (!(port->flags & ASYNC_CLOSING) &&
+                               (do_clocal || cd))
+                       break;
+               if (signal_pending(current)) {
+                       retval = -ERESTARTSYS;
+                       break;
+               }
+               schedule();
+       }
+       set_current_state(TASK_RUNNING);
+       remove_wait_queue(&port->open_wait, &wait);
+
+       /* Update counts. A parallel hangup will have set count to zero and
+          we must not mess that up further */
+       spin_lock_irqsave(&port->lock, flags);
+       if (!tty_hung_up_p(filp))
+               port->count++;
+       port->blocked_open--;
+       if (retval == 0)
+               port->flags |= ASYNC_NORMAL_ACTIVE;
+       spin_unlock_irqrestore(&port->lock, flags);
+       return 0;
+       
+}
+EXPORT_SYMBOL(tty_port_block_til_ready);
+
+int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, struct file *filp)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       if (tty_hung_up_p(filp)) {
+               spin_unlock_irqrestore(&port->lock, flags);
+               return 0;
+       }
+
+       if( tty->count == 1 && port->count != 1) {
+               printk(KERN_WARNING
+                   "tty_port_close_start: tty->count = 1 port count = %d.\n",
+                                                               port->count);
+               port->count = 1;
+       }
+       if (--port->count < 0) {
+               printk(KERN_WARNING "tty_port_close_start: count = %d\n",
+                                                               port->count);
+               port->count = 0;
+       }
+
+       if (port->count) {
+               spin_unlock_irqrestore(&port->lock, flags);
+               return 0;
+       }
+       port->flags |= ASYNC_CLOSING;
+       tty->closing = 1;
+       spin_unlock_irqrestore(&port->lock, flags);
+       /* Don't block on a stalled port, just pull the chain */
+       if (tty->flow_stopped)
+               tty_driver_flush_buffer(tty);
+       if (port->flags & ASYNC_INITIALIZED &&
+                       port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+               tty_wait_until_sent(tty, port->closing_wait);
+       return 1;
+}
+EXPORT_SYMBOL(tty_port_close_start);
+
+void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
+{
+       unsigned long flags;
+
+       tty_ldisc_flush(tty);
+
+       spin_lock_irqsave(&port->lock, flags);
+       tty->closing = 0;
+
+       if (port->blocked_open) {
+               spin_unlock_irqrestore(&port->lock, flags);
+               if (port->close_delay) {
+                       msleep_interruptible(
+                               jiffies_to_msecs(port->close_delay));
+               }
+               spin_lock_irqsave(&port->lock, flags);
+               wake_up_interruptible(&port->open_wait);
+       }
+       port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
+       wake_up_interruptible(&port->close_wait);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+EXPORT_SYMBOL(tty_port_close_end);
index 1718b3c481dbd944eb343b140801e930dd5cc355..0e8234bd0e19b6d178658dcd6e698d9d6f217854 100644 (file)
@@ -69,7 +69,7 @@ static void scc_disable_tx_interrupts(void * ptr);
 static void scc_enable_tx_interrupts(void * ptr);
 static void scc_disable_rx_interrupts(void * ptr);
 static void scc_enable_rx_interrupts(void * ptr);
-static int  scc_get_CD(void * ptr);
+static int  scc_carrier_raised(struct tty_port *port);
 static void scc_shutdown_port(void * ptr);
 static int scc_set_real_termios(void  *ptr);
 static void scc_hungup(void  *ptr);
@@ -100,7 +100,6 @@ static struct real_driver scc_real_driver = {
         scc_enable_tx_interrupts,
         scc_disable_rx_interrupts,
         scc_enable_rx_interrupts,
-        scc_get_CD,
         scc_shutdown_port,
         scc_set_real_termios,
         scc_chars_in_buffer,
@@ -129,6 +128,10 @@ static const struct tty_operations scc_ops = {
        .break_ctl = scc_break_ctl,
 };
 
+static const struct tty_port_operations scc_port_ops = {
+       .carrier_raised = scc_carrier_raised,
+};
+
 /*----------------------------------------------------------------------------
  * vme_scc_init() and support functions
  *---------------------------------------------------------------------------*/
@@ -176,6 +179,8 @@ static void scc_init_portstructs(void)
 
        for (i = 0; i < 2; i++) {
                port = scc_ports + i;
+               tty_port_init(&port->gs.port);
+               port->gs.port.ops = &scc_port_ops;
                port->gs.magic = SCC_MAGIC;
                port->gs.close_delay = HZ/2;
                port->gs.closing_wait = 30 * HZ;
@@ -624,10 +629,10 @@ static void scc_enable_rx_interrupts(void *ptr)
 }
 
 
-static int scc_get_CD(void *ptr)
+static int scc_carrier_raised(struct tty_port *port)
 {
-       struct scc_port *port = ptr;
-       unsigned channel = port->channel;
+       struct scc_port *sc = container_of(port, struct scc_port, gs.port);
+       unsigned channel = sc->channel;
 
        return !!(scc_last_status_reg[channel] & SR_DCD);
 }
@@ -638,7 +643,7 @@ static void scc_shutdown_port(void *ptr)
        struct scc_port *port = ptr;
 
        port->gs.port.flags &= ~ GS_ACTIVE;
-       if (port->gs.port.tty && port->gs.port.tty->termios->c_cflag & HUPCL) {
+       if (port->gs.port.tty && (port->gs.port.tty->termios->c_cflag & HUPCL)) {
                scc_setsignals (port, 0, 0);
        }
 }
@@ -779,7 +784,7 @@ static void scc_setsignals(struct scc_port *port, int dtr, int rts)
 
 static void scc_send_xchar(struct tty_struct *tty, char ch)
 {
-       struct scc_port *port = (struct scc_port *)tty->driver_data;
+       struct scc_port *port = tty->driver_data;
 
        port->x_char = ch;
        if (ch)
@@ -896,7 +901,7 @@ static int scc_open (struct tty_struct * tty, struct file * filp)
                return retval;
        }
 
-       port->c_dcd = scc_get_CD (port);
+       port->c_dcd = tty_port_carrier_raised(&port->gs.port);
 
        scc_enable_rx_interrupts(port);
 
@@ -906,7 +911,7 @@ static int scc_open (struct tty_struct * tty, struct file * filp)
 
 static void scc_throttle (struct tty_struct * tty)
 {
-       struct scc_port *port = (struct scc_port *)tty->driver_data;
+       struct scc_port *port = tty->driver_data;
        unsigned long   flags;
        SCC_ACCESS_INIT(port);
 
@@ -922,7 +927,7 @@ static void scc_throttle (struct tty_struct * tty)
 
 static void scc_unthrottle (struct tty_struct * tty)
 {
-       struct scc_port *port = (struct scc_port *)tty->driver_data;
+       struct scc_port *port = tty->driver_data;
        unsigned long   flags;
        SCC_ACCESS_INIT(port);
 
@@ -945,7 +950,7 @@ static int scc_ioctl(struct tty_struct *tty, struct file *file,
 
 static int scc_break_ctl(struct tty_struct *tty, int break_state)
 {
-       struct scc_port *port = (struct scc_port *)tty->driver_data;
+       struct scc_port *port = tty->driver_data;
        unsigned long   flags;
        SCC_ACCESS_INIT(port);
 
index 008176edbd64511148ac5e1e40d21d3fbf1883d5..80014213fb5397a7c7694e5b4c023b6e308bb197 100644 (file)
@@ -819,8 +819,8 @@ static inline int resize_screen(struct vc_data *vc, int width, int height,
  *     ctrl_lock of the tty IFF a tty is passed.
  */
 
-static int vc_do_resize(struct tty_struct *tty, struct tty_struct *real_tty,
-               struct vc_data *vc, unsigned int cols, unsigned int lines)
+static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
+                               unsigned int cols, unsigned int lines)
 {
        unsigned long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0;
        unsigned int old_cols, old_rows, old_row_size, old_screen_size;
@@ -932,7 +932,7 @@ static int vc_do_resize(struct tty_struct *tty, struct tty_struct *real_tty,
                ws.ws_row = vc->vc_rows;
                ws.ws_col = vc->vc_cols;
                ws.ws_ypixel = vc->vc_scan_lines;
-               tty_do_resize(tty, real_tty, &ws);
+               tty_do_resize(tty, &ws);
        }
 
        if (CON_IS_VISIBLE(vc))
@@ -954,13 +954,12 @@ static int vc_do_resize(struct tty_struct *tty, struct tty_struct *real_tty,
 
 int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int rows)
 {
-       return vc_do_resize(vc->vc_tty, vc->vc_tty, vc, cols, rows);
+       return vc_do_resize(vc->vc_tty, vc, cols, rows);
 }
 
 /**
  *     vt_resize               -       resize a VT
  *     @tty: tty to resize
- *     @real_tty: tty if a pty/tty pair
  *     @ws: winsize attributes
  *
  *     Resize a virtual terminal. This is called by the tty layer as we
@@ -971,14 +970,13 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int rows)
  *     termios_mutex and the tty ctrl_lock in that order.
  */
 
-int vt_resize(struct tty_struct *tty, struct tty_struct *real_tty,
-       struct winsize *ws)
+int vt_resize(struct tty_struct *tty, struct winsize *ws)
 {
        struct vc_data *vc = tty->driver_data;
        int ret;
 
        acquire_console_sem();
-       ret = vc_do_resize(tty, real_tty, vc, ws->ws_col, ws->ws_row);
+       ret = vc_do_resize(tty, vc, ws->ws_col, ws->ws_row);
        release_console_sem();
        return ret;
 }
@@ -2679,7 +2677,7 @@ static int con_write_room(struct tty_struct *tty)
 {
        if (tty->stopped)
                return 0;
-       return 4096;            /* No limit, really; we're not buffering */
+       return 32768;           /* No limit, really; we're not buffering */
 }
 
 static int con_chars_in_buffer(struct tty_struct *tty)
index 8944ce508e2fea56a489501023a7dcdc8a22bb81..a2dee0eb6dadb5f39b05a9361c37d95b1383faaa 100644 (file)
@@ -366,7 +366,7 @@ do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud, int perm, struct vc_
 int vt_ioctl(struct tty_struct *tty, struct file * file,
             unsigned int cmd, unsigned long arg)
 {
-       struct vc_data *vc = (struct vc_data *)tty->driver_data;
+       struct vc_data *vc = tty->driver_data;
        struct console_font_op op;      /* used in multiple places here */
        struct kbd_struct * kbd;
        unsigned int console;
index 9f7896a25f1bfb6df80e1d16db0641305f5e8259..c4918b86ed193cb4647510b950e114d952a627fd 100644 (file)
@@ -3,6 +3,8 @@
  * Driver for Option High Speed Mobile Devices.
  *
  *  Copyright (C) 2008 Option International
+ *                     Filip Aben <f.aben@option.com>
+ *                     Denis Joseph Barrow <d.barow@option.com>
  *  Copyright (C) 2007 Andrew Bird (Sphere Systems Ltd)
  *                     <ajb@spheresystems.co.uk>
  *  Copyright (C) 2008 Greg Kroah-Hartman <gregkh@suse.de>
  *             port is opened, as this have a huge impact on the network port
  *             throughput.
  *
- * Interface 2:        Standard modem interface - circuit switched interface, should
- *             not be used.
+ * Interface 2:        Standard modem interface - circuit switched interface, this
+ *             can be used to make a standard ppp connection however it
+ *              should not be used in conjunction with the IP network interface
+ *              enabled for USB performance reasons i.e. if using this set
+ *              ideally disable_net=1.
  *
  *****************************************************************************/
 
@@ -63,6 +68,8 @@
 #include <linux/usb/cdc.h>
 #include <net/arp.h>
 #include <asm/byteorder.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
 
 
 #define DRIVER_VERSION                 "1.2"
@@ -182,6 +189,41 @@ enum rx_ctrl_state{
        RX_PENDING
 };
 
+#define BM_REQUEST_TYPE (0xa1)
+#define B_NOTIFICATION  (0x20)
+#define W_VALUE         (0x0)
+#define W_INDEX         (0x2)
+#define W_LENGTH        (0x2)
+
+#define B_OVERRUN       (0x1<<6)
+#define B_PARITY        (0x1<<5)
+#define B_FRAMING       (0x1<<4)
+#define B_RING_SIGNAL   (0x1<<3)
+#define B_BREAK         (0x1<<2)
+#define B_TX_CARRIER    (0x1<<1)
+#define B_RX_CARRIER    (0x1<<0)
+
+struct hso_serial_state_notification {
+       u8 bmRequestType;
+       u8 bNotification;
+       u16 wValue;
+       u16 wIndex;
+       u16 wLength;
+       u16 UART_state_bitmap;
+} __attribute__((packed));
+
+struct hso_tiocmget {
+       struct mutex mutex;
+       wait_queue_head_t waitq;
+       int    intr_completed;
+       struct usb_endpoint_descriptor *endp;
+       struct urb *urb;
+       struct hso_serial_state_notification serial_state_notification;
+       u16    prev_UART_state_bitmap;
+       struct uart_icount icount;
+};
+
+
 struct hso_serial {
        struct hso_device *parent;
        int magic;
@@ -219,6 +261,7 @@ struct hso_serial {
        spinlock_t serial_lock;
 
        int (*write_data) (struct hso_serial *serial);
+       struct hso_tiocmget  *tiocmget;
        /* Hacks required to get flow control
         * working on the serial receive buffers
         * so as not to drop characters on the floor.
@@ -305,7 +348,7 @@ static void async_get_intf(struct work_struct *data);
 static void async_put_intf(struct work_struct *data);
 static int hso_put_activity(struct hso_device *hso_dev);
 static int hso_get_activity(struct hso_device *hso_dev);
-
+static void tiocmget_intr_callback(struct urb *urb);
 /*****************************************************************************/
 /* Helping functions                                                         */
 /*****************************************************************************/
@@ -362,8 +405,6 @@ static struct tty_driver *tty_drv;
 static struct hso_device *serial_table[HSO_SERIAL_TTY_MINORS];
 static struct hso_device *network_table[HSO_MAX_NET_DEVICES];
 static spinlock_t serial_table_lock;
-static struct ktermios *hso_serial_termios[HSO_SERIAL_TTY_MINORS];
-static struct ktermios *hso_serial_termios_locked[HSO_SERIAL_TTY_MINORS];
 
 static const s32 default_port_spec[] = {
        HSO_INTF_MUX | HSO_PORT_NETWORK,
@@ -1009,23 +1050,11 @@ static void read_bulk_callback(struct urb *urb)
 
 /* Serial driver functions */
 
-static void _hso_serial_set_termios(struct tty_struct *tty,
-                                   struct ktermios *old)
+static void hso_init_termios(struct ktermios *termios)
 {
-       struct hso_serial *serial = get_serial_by_tty(tty);
-       struct ktermios *termios;
-
-       if ((!tty) || (!tty->termios) || (!serial)) {
-               printk(KERN_ERR "%s: no tty structures", __func__);
-               return;
-       }
-
-       D4("port %d", serial->minor);
-
        /*
         * The default requirements for this device are:
         */
-       termios = tty->termios;
        termios->c_iflag &=
                ~(IGNBRK        /* disable ignore break */
                | BRKINT        /* disable break causes interrupt */
@@ -1057,15 +1086,38 @@ static void _hso_serial_set_termios(struct tty_struct *tty,
        termios->c_cflag |= CS8;        /* character size 8 bits */
 
        /* baud rate 115200 */
-       tty_encode_baud_rate(serial->tty, 115200, 115200);
+       tty_termios_encode_baud_rate(termios, 115200, 115200);
+}
+
+static void _hso_serial_set_termios(struct tty_struct *tty,
+                                   struct ktermios *old)
+{
+       struct hso_serial *serial = get_serial_by_tty(tty);
+       struct ktermios *termios;
+
+       if (!serial) {
+               printk(KERN_ERR "%s: no tty structures", __func__);
+               return;
+       }
+
+       D4("port %d", serial->minor);
 
        /*
-        * Force low_latency on; otherwise the pushes are scheduled;
-        * this is bad as it opens up the possibility of dropping bytes
-        * on the floor.  We don't want to drop bytes on the floor. :)
+        *      Fix up unsupported bits
         */
-       serial->tty->low_latency = 1;
-       return;
+       termios = tty->termios;
+       termios->c_iflag &= ~IXON; /* disable enable XON/XOFF flow control */
+
+       termios->c_cflag &=
+               ~(CSIZE         /* no size */
+               | PARENB        /* disable parity bit */
+               | CBAUD         /* clear current baud rate */
+               | CBAUDEX);     /* clear current buad rate */
+
+       termios->c_cflag |= CS8;        /* character size 8 bits */
+
+       /* baud rate 115200 */
+       tty_encode_baud_rate(tty, 115200, 115200);
 }
 
 static void hso_resubmit_rx_bulk_urb(struct hso_serial *serial, struct urb *urb)
@@ -1228,6 +1280,7 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp)
 
        /* sanity check */
        if (serial == NULL || serial->magic != HSO_SERIAL_MAGIC) {
+               WARN_ON(1);
                tty->driver_data = NULL;
                D1("Failed to open port");
                return -ENODEV;
@@ -1242,8 +1295,10 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp)
        kref_get(&serial->parent->ref);
 
        /* setup */
+       spin_lock_irq(&serial->serial_lock);
        tty->driver_data = serial;
-       serial->tty = tty;
+       serial->tty = tty_kref_get(tty);
+       spin_unlock_irq(&serial->serial_lock);
 
        /* check for port already opened, if not set the termios */
        serial->open_count++;
@@ -1285,6 +1340,10 @@ static void hso_serial_close(struct tty_struct *tty, struct file *filp)
 
        D1("Closing serial port");
 
+       /* Open failed, no close cleanup required */
+       if (serial == NULL)
+               return;
+
        mutex_lock(&serial->parent->mutex);
        usb_gone = serial->parent->usb_gone;
 
@@ -1297,10 +1356,13 @@ static void hso_serial_close(struct tty_struct *tty, struct file *filp)
        kref_put(&serial->parent->ref, hso_serial_ref_free);
        if (serial->open_count <= 0) {
                serial->open_count = 0;
-               if (serial->tty) {
+               spin_lock_irq(&serial->serial_lock);
+               if (serial->tty == tty) {
                        serial->tty->driver_data = NULL;
                        serial->tty = NULL;
+                       tty_kref_put(tty);
                }
+               spin_unlock_irq(&serial->serial_lock);
                if (!usb_gone)
                        hso_stop_serial_device(serial->parent);
                tasklet_kill(&serial->unthrottle_tasklet);
@@ -1400,25 +1462,217 @@ static int hso_serial_chars_in_buffer(struct tty_struct *tty)
 
        return chars;
 }
+int tiocmget_submit_urb(struct hso_serial *serial,
+                       struct hso_tiocmget  *tiocmget,
+                       struct usb_device *usb)
+{
+       int result;
+
+       if (serial->parent->usb_gone)
+               return -ENODEV;
+       usb_fill_int_urb(tiocmget->urb, usb,
+                        usb_rcvintpipe(usb,
+                                       tiocmget->endp->
+                                       bEndpointAddress & 0x7F),
+                        &tiocmget->serial_state_notification,
+                        sizeof(struct hso_serial_state_notification),
+                        tiocmget_intr_callback, serial,
+                        tiocmget->endp->bInterval);
+       result = usb_submit_urb(tiocmget->urb, GFP_ATOMIC);
+       if (result) {
+               dev_warn(&usb->dev, "%s usb_submit_urb failed %d\n", __func__,
+                        result);
+       }
+       return result;
+
+}
+
+static void tiocmget_intr_callback(struct urb *urb)
+{
+       struct hso_serial *serial = urb->context;
+       struct hso_tiocmget *tiocmget;
+       int status = urb->status;
+       u16 UART_state_bitmap, prev_UART_state_bitmap;
+       struct uart_icount *icount;
+       struct hso_serial_state_notification *serial_state_notification;
+       struct usb_device *usb;
+
+       /* Sanity checks */
+       if (!serial)
+               return;
+       if (status) {
+               log_usb_status(status, __func__);
+               return;
+       }
+       tiocmget = serial->tiocmget;
+       if (!tiocmget)
+               return;
+       usb = serial->parent->usb;
+       serial_state_notification = &tiocmget->serial_state_notification;
+       if (serial_state_notification->bmRequestType != BM_REQUEST_TYPE ||
+           serial_state_notification->bNotification != B_NOTIFICATION ||
+           le16_to_cpu(serial_state_notification->wValue) != W_VALUE ||
+           le16_to_cpu(serial_state_notification->wIndex) != W_INDEX ||
+           le16_to_cpu(serial_state_notification->wLength) != W_LENGTH) {
+               dev_warn(&usb->dev,
+                        "hso received invalid serial state notification\n");
+               DUMP(serial_state_notification,
+                    sizeof(hso_serial_state_notifation))
+       } else {
+
+               UART_state_bitmap = le16_to_cpu(serial_state_notification->
+                                               UART_state_bitmap);
+               prev_UART_state_bitmap = tiocmget->prev_UART_state_bitmap;
+               icount = &tiocmget->icount;
+               spin_lock(&serial->serial_lock);
+               if ((UART_state_bitmap & B_OVERRUN) !=
+                  (prev_UART_state_bitmap & B_OVERRUN))
+                       icount->parity++;
+               if ((UART_state_bitmap & B_PARITY) !=
+                  (prev_UART_state_bitmap & B_PARITY))
+                       icount->parity++;
+               if ((UART_state_bitmap & B_FRAMING) !=
+                  (prev_UART_state_bitmap & B_FRAMING))
+                       icount->frame++;
+               if ((UART_state_bitmap & B_RING_SIGNAL) &&
+                  !(prev_UART_state_bitmap & B_RING_SIGNAL))
+                       icount->rng++;
+               if ((UART_state_bitmap & B_BREAK) !=
+                  (prev_UART_state_bitmap & B_BREAK))
+                       icount->brk++;
+               if ((UART_state_bitmap & B_TX_CARRIER) !=
+                  (prev_UART_state_bitmap & B_TX_CARRIER))
+                       icount->dsr++;
+               if ((UART_state_bitmap & B_RX_CARRIER) !=
+                  (prev_UART_state_bitmap & B_RX_CARRIER))
+                       icount->dcd++;
+               tiocmget->prev_UART_state_bitmap = UART_state_bitmap;
+               spin_unlock(&serial->serial_lock);
+               tiocmget->intr_completed = 1;
+               wake_up_interruptible(&tiocmget->waitq);
+       }
+       memset(serial_state_notification, 0,
+              sizeof(struct hso_serial_state_notification));
+       tiocmget_submit_urb(serial,
+                           tiocmget,
+                           serial->parent->usb);
+}
+
+/*
+ * next few functions largely stolen from drivers/serial/serial_core.c
+ */
+/* 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
+ */
+static int
+hso_wait_modem_status(struct hso_serial *serial, unsigned long arg)
+{
+       DECLARE_WAITQUEUE(wait, current);
+       struct uart_icount cprev, cnow;
+       struct hso_tiocmget  *tiocmget;
+       int ret;
+
+       tiocmget = serial->tiocmget;
+       if (!tiocmget)
+               return -ENOENT;
+       /*
+        * note the counters on entry
+        */
+       spin_lock_irq(&serial->serial_lock);
+       memcpy(&cprev, &tiocmget->icount, sizeof(struct uart_icount));
+       spin_unlock_irq(&serial->serial_lock);
+       add_wait_queue(&tiocmget->waitq, &wait);
+       for (;;) {
+               spin_lock_irq(&serial->serial_lock);
+               memcpy(&cnow, &tiocmget->icount, sizeof(struct uart_icount));
+               spin_unlock_irq(&serial->serial_lock);
+               set_current_state(TASK_INTERRUPTIBLE);
+               if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
+                   ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
+                   ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd))) {
+                       ret = 0;
+                       break;
+               }
+               schedule();
+               /* see if a signal did it */
+               if (signal_pending(current)) {
+                       ret = -ERESTARTSYS;
+                       break;
+               }
+               cprev = cnow;
+       }
+       current->state = TASK_RUNNING;
+       remove_wait_queue(&tiocmget->waitq, &wait);
+
+       return ret;
+}
+
+/*
+ * 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.
+ */
+static int hso_get_count(struct hso_serial *serial,
+                         struct serial_icounter_struct __user *icnt)
+{
+       struct serial_icounter_struct icount;
+       struct uart_icount cnow;
+       struct hso_tiocmget  *tiocmget = serial->tiocmget;
+
+       if (!tiocmget)
+                return -ENOENT;
+       spin_lock_irq(&serial->serial_lock);
+       memcpy(&cnow, &tiocmget->icount, sizeof(struct uart_icount));
+       spin_unlock_irq(&serial->serial_lock);
+
+       icount.cts         = cnow.cts;
+       icount.dsr         = cnow.dsr;
+       icount.rng         = cnow.rng;
+       icount.dcd         = cnow.dcd;
+       icount.rx          = cnow.rx;
+       icount.tx          = cnow.tx;
+       icount.frame       = cnow.frame;
+       icount.overrun     = cnow.overrun;
+       icount.parity      = cnow.parity;
+       icount.brk         = cnow.brk;
+       icount.buf_overrun = cnow.buf_overrun;
+
+       return copy_to_user(icnt, &icount, sizeof(icount)) ? -EFAULT : 0;
+}
+
 
 static int hso_serial_tiocmget(struct tty_struct *tty, struct file *file)
 {
-       unsigned int value;
+       int retval;
        struct hso_serial *serial = get_serial_by_tty(tty);
-       unsigned long flags;
+       struct hso_tiocmget  *tiocmget;
+       u16 UART_state_bitmap;
 
        /* sanity check */
        if (!serial) {
                D1("no tty structures");
                return -EINVAL;
        }
-
-       spin_lock_irqsave(&serial->serial_lock, flags);
-       value = ((serial->rts_state) ? TIOCM_RTS : 0) |
+       spin_lock_irq(&serial->serial_lock);
+       retval = ((serial->rts_state) ? TIOCM_RTS : 0) |
            ((serial->dtr_state) ? TIOCM_DTR : 0);
-       spin_unlock_irqrestore(&serial->serial_lock, flags);
+       tiocmget = serial->tiocmget;
+       if (tiocmget) {
 
-       return value;
+               UART_state_bitmap = le16_to_cpu(
+                       tiocmget->prev_UART_state_bitmap);
+               if (UART_state_bitmap & B_RING_SIGNAL)
+                       retval |=  TIOCM_RNG;
+               if (UART_state_bitmap & B_RX_CARRIER)
+                       retval |=  TIOCM_CD;
+               if (UART_state_bitmap & B_TX_CARRIER)
+                       retval |=  TIOCM_DSR;
+       }
+       spin_unlock_irq(&serial->serial_lock);
+       return retval;
 }
 
 static int hso_serial_tiocmset(struct tty_struct *tty, struct file *file,
@@ -1460,6 +1714,32 @@ static int hso_serial_tiocmset(struct tty_struct *tty, struct file *file,
                               USB_CTRL_SET_TIMEOUT);
 }
 
+static int hso_serial_ioctl(struct tty_struct *tty, struct file *file,
+                           unsigned int cmd, unsigned long arg)
+{
+       struct hso_serial *serial =  get_serial_by_tty(tty);
+       void __user *uarg = (void __user *)arg;
+       int ret = 0;
+       D4("IOCTL cmd: %d, arg: %ld", cmd, arg);
+
+       if (!serial)
+               return -ENODEV;
+       switch (cmd) {
+       case TIOCMIWAIT:
+               ret = hso_wait_modem_status(serial, arg);
+               break;
+
+       case TIOCGICOUNT:
+               ret = hso_get_count(serial, uarg);
+               break;
+       default:
+               ret = -ENOIOCTLCMD;
+               break;
+       }
+       return ret;
+}
+
+
 /* starts a transmit */
 static void hso_kick_transmit(struct hso_serial *serial)
 {
@@ -1653,6 +1933,7 @@ static void hso_std_serial_write_bulk_callback(struct urb *urb)
 {
        struct hso_serial *serial = urb->context;
        int status = urb->status;
+       struct tty_struct *tty;
 
        /* sanity check */
        if (!serial) {
@@ -1662,14 +1943,18 @@ static void hso_std_serial_write_bulk_callback(struct urb *urb)
 
        spin_lock(&serial->serial_lock);
        serial->tx_urb_used = 0;
+       tty = tty_kref_get(serial->tty);
        spin_unlock(&serial->serial_lock);
        if (status) {
                log_usb_status(status, __func__);
+               tty_kref_put(tty);
                return;
        }
        hso_put_activity(serial->parent);
-       if (serial->tty)
-               tty_wakeup(serial->tty);
+       if (tty) {
+               tty_wakeup(tty);
+               tty_kref_put(tty);
+       }
        hso_kick_transmit(serial);
 
        D1(" ");
@@ -1706,6 +1991,7 @@ static void ctrl_callback(struct urb *urb)
        struct hso_serial *serial = urb->context;
        struct usb_ctrlrequest *req;
        int status = urb->status;
+       struct tty_struct *tty;
 
        /* sanity check */
        if (!serial)
@@ -1713,9 +1999,11 @@ static void ctrl_callback(struct urb *urb)
 
        spin_lock(&serial->serial_lock);
        serial->tx_urb_used = 0;
+       tty = tty_kref_get(serial->tty);
        spin_unlock(&serial->serial_lock);
        if (status) {
                log_usb_status(status, __func__);
+               tty_kref_put(tty);
                return;
        }
 
@@ -1734,25 +2022,31 @@ static void ctrl_callback(struct urb *urb)
                spin_unlock(&serial->serial_lock);
        } else {
                hso_put_activity(serial->parent);
-               if (serial->tty)
-                       tty_wakeup(serial->tty);
+               if (tty)
+                       tty_wakeup(tty);
                /* response to a write command */
                hso_kick_transmit(serial);
        }
+       tty_kref_put(tty);
 }
 
 /* handle RX data for serial port */
 static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial)
 {
-       struct tty_struct *tty = serial->tty;
+       struct tty_struct *tty;
        int write_length_remaining = 0;
        int curr_write_len;
+
        /* Sanity check */
        if (urb == NULL || serial == NULL) {
                D1("serial = NULL");
                return -2;
        }
 
+       spin_lock(&serial->serial_lock);
+       tty = tty_kref_get(serial->tty);
+       spin_unlock(&serial->serial_lock);
+
        /* Push data to tty */
        if (tty) {
                write_length_remaining = urb->actual_length -
@@ -1774,6 +2068,7 @@ static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial)
                serial->curr_rx_urb_offset = 0;
                serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0;
        }
+       tty_kref_put(tty);
        return write_length_remaining;
 }
 
@@ -1922,7 +2217,10 @@ static int hso_start_serial_device(struct hso_device *hso_dev, gfp_t flags)
                serial->shared_int->use_count++;
                mutex_unlock(&serial->shared_int->shared_int_lock);
        }
-
+       if (serial->tiocmget)
+               tiocmget_submit_urb(serial,
+                                   serial->tiocmget,
+                                   serial->parent->usb);
        return result;
 }
 
@@ -1930,6 +2228,7 @@ static int hso_stop_serial_device(struct hso_device *hso_dev)
 {
        int i;
        struct hso_serial *serial = dev2ser(hso_dev);
+       struct hso_tiocmget  *tiocmget;
 
        if (!serial)
                return -ENODEV;
@@ -1958,6 +2257,11 @@ static int hso_stop_serial_device(struct hso_device *hso_dev)
                }
                mutex_unlock(&serial->shared_int->shared_int_lock);
        }
+       tiocmget = serial->tiocmget;
+       if (tiocmget) {
+               wake_up_interruptible(&tiocmget->waitq);
+               usb_kill_urb(tiocmget->urb);
+       }
 
        return 0;
 }
@@ -2304,6 +2608,20 @@ exit:
        return NULL;
 }
 
+static void hso_free_tiomget(struct hso_serial *serial)
+{
+       struct hso_tiocmget *tiocmget = serial->tiocmget;
+       if (tiocmget) {
+               kfree(tiocmget);
+               if (tiocmget->urb) {
+                       usb_free_urb(tiocmget->urb);
+                       tiocmget->urb = NULL;
+               }
+               serial->tiocmget = NULL;
+
+       }
+}
+
 /* Frees an AT channel ( goes for both mux and non-mux ) */
 static void hso_free_serial_device(struct hso_device *hso_dev)
 {
@@ -2322,6 +2640,7 @@ static void hso_free_serial_device(struct hso_device *hso_dev)
                else
                        mutex_unlock(&serial->shared_int->shared_int_lock);
        }
+       hso_free_tiomget(serial);
        kfree(serial);
        hso_free_device(hso_dev);
 }
@@ -2333,6 +2652,7 @@ static struct hso_device *hso_create_bulk_serial_device(
        struct hso_device *hso_dev;
        struct hso_serial *serial;
        int num_urbs;
+       struct hso_tiocmget *tiocmget;
 
        hso_dev = hso_create_device(interface, port);
        if (!hso_dev)
@@ -2345,8 +2665,27 @@ static struct hso_device *hso_create_bulk_serial_device(
        serial->parent = hso_dev;
        hso_dev->port_data.dev_serial = serial;
 
-       if (port & HSO_PORT_MODEM)
+       if ((port & HSO_PORT_MASK) == HSO_PORT_MODEM) {
                num_urbs = 2;
+               serial->tiocmget = kzalloc(sizeof(struct hso_tiocmget),
+                                          GFP_KERNEL);
+               /* it isn't going to break our heart if serial->tiocmget
+                *  allocation fails don't bother checking this.
+                */
+               if (serial->tiocmget) {
+                       tiocmget = serial->tiocmget;
+                       tiocmget->urb = usb_alloc_urb(0, GFP_KERNEL);
+                       if (tiocmget->urb) {
+                               mutex_init(&tiocmget->mutex);
+                               init_waitqueue_head(&tiocmget->waitq);
+                               tiocmget->endp = hso_get_ep(
+                                       interface,
+                                       USB_ENDPOINT_XFER_INT,
+                                       USB_DIR_IN);
+                       } else
+                               hso_free_tiomget(serial);
+               }
+       }
        else
                num_urbs = 1;
 
@@ -2382,6 +2721,7 @@ static struct hso_device *hso_create_bulk_serial_device(
 exit2:
        hso_serial_common_free(serial);
 exit:
+       hso_free_tiomget(serial);
        kfree(serial);
        hso_free_device(hso_dev);
        return NULL;
@@ -2786,15 +3126,20 @@ static void hso_serial_ref_free(struct kref *ref)
 static void hso_free_interface(struct usb_interface *interface)
 {
        struct hso_serial *hso_dev;
+       struct tty_struct *tty;
        int i;
 
        for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) {
                if (serial_table[i]
                    && (serial_table[i]->interface == interface)) {
                        hso_dev = dev2ser(serial_table[i]);
-                       if (hso_dev->tty)
-                               tty_hangup(hso_dev->tty);
+                       spin_lock_irq(&hso_dev->serial_lock);
+                       tty = tty_kref_get(hso_dev->tty);
+                       spin_unlock_irq(&hso_dev->serial_lock);
+                       if (tty)
+                               tty_hangup(tty);
                        mutex_lock(&hso_dev->parent->mutex);
+                       tty_kref_put(tty);
                        hso_dev->parent->usb_gone = 1;
                        mutex_unlock(&hso_dev->parent->mutex);
                        kref_put(&serial_table[i]->ref, hso_serial_ref_free);
@@ -2887,6 +3232,7 @@ static const struct tty_operations hso_serial_ops = {
        .close = hso_serial_close,
        .write = hso_serial_write,
        .write_room = hso_serial_write_room,
+       .ioctl = hso_serial_ioctl,
        .set_termios = hso_serial_set_termios,
        .chars_in_buffer = hso_serial_chars_in_buffer,
        .tiocmget = hso_serial_tiocmget,
@@ -2939,9 +3285,7 @@ static int __init hso_init(void)
        tty_drv->subtype = SERIAL_TYPE_NORMAL;
        tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
        tty_drv->init_termios = tty_std_termios;
-       tty_drv->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-       tty_drv->termios = hso_serial_termios;
-       tty_drv->termios_locked = hso_serial_termios_locked;
+       hso_init_termios(&tty_drv->init_termios);
        tty_set_operations(tty_drv, &hso_serial_ops);
 
        /* register the tty driver */
index 303272af386ef4ac307517d6df654759cbc23d43..daa00567bc44115577ff012cac16985c2957b66f 100644 (file)
@@ -279,6 +279,13 @@ static const struct serial8250_config uart_config[] = {
                .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
                .flags          = UART_CAP_FIFO,
        },
+       [PORT_OCTEON] = {
+               .name           = "OCTEON",
+               .fifo_size      = 64,
+               .tx_loadsz      = 64,
+               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
+               .flags          = UART_CAP_FIFO,
+       },
 };
 
 #if defined (CONFIG_SERIAL_8250_AU1X00)
@@ -303,16 +310,16 @@ static const u8 au_io_out_map[] = {
 };
 
 /* sane hardware needs no mapping */
-static inline int map_8250_in_reg(struct uart_8250_port *up, int offset)
+static inline int map_8250_in_reg(struct uart_port *p, int offset)
 {
-       if (up->port.iotype != UPIO_AU)
+       if (p->iotype != UPIO_AU)
                return offset;
        return au_io_in_map[offset];
 }
 
-static inline int map_8250_out_reg(struct uart_8250_port *up, int offset)
+static inline int map_8250_out_reg(struct uart_port *p, int offset)
 {
-       if (up->port.iotype != UPIO_AU)
+       if (p->iotype != UPIO_AU)
                return offset;
        return au_io_out_map[offset];
 }
@@ -341,16 +348,16 @@ static const u8
                [UART_SCR]      = 0x2c
        };
 
-static inline int map_8250_in_reg(struct uart_8250_port *up, int offset)
+static inline int map_8250_in_reg(struct uart_port *p, int offset)
 {
-       if (up->port.iotype != UPIO_RM9000)
+       if (p->iotype != UPIO_RM9000)
                return offset;
        return regmap_in[offset];
 }
 
-static inline int map_8250_out_reg(struct uart_8250_port *up, int offset)
+static inline int map_8250_out_reg(struct uart_port *p, int offset)
 {
-       if (up->port.iotype != UPIO_RM9000)
+       if (p->iotype != UPIO_RM9000)
                return offset;
        return regmap_out[offset];
 }
@@ -363,108 +370,170 @@ static inline int map_8250_out_reg(struct uart_8250_port *up, int offset)
 
 #endif
 
-static unsigned int serial_in(struct uart_8250_port *up, int offset)
+static unsigned int hub6_serial_in(struct uart_port *p, int offset)
 {
-       unsigned int tmp;
-       offset = map_8250_in_reg(up, offset) << up->port.regshift;
+       offset = map_8250_in_reg(p, offset) << p->regshift;
+       outb(p->hub6 - 1 + offset, p->iobase);
+       return inb(p->iobase + 1);
+}
 
-       switch (up->port.iotype) {
-       case UPIO_HUB6:
-               outb(up->port.hub6 - 1 + offset, up->port.iobase);
-               return inb(up->port.iobase + 1);
+static void hub6_serial_out(struct uart_port *p, int offset, int value)
+{
+       offset = map_8250_out_reg(p, offset) << p->regshift;
+       outb(p->hub6 - 1 + offset, p->iobase);
+       outb(value, p->iobase + 1);
+}
 
-       case UPIO_MEM:
-       case UPIO_DWAPB:
-               return readb(up->port.membase + offset);
+static unsigned int mem_serial_in(struct uart_port *p, int offset)
+{
+       offset = map_8250_in_reg(p, offset) << p->regshift;
+       return readb(p->membase + offset);
+}
 
-       case UPIO_RM9000:
-       case UPIO_MEM32:
-               return readl(up->port.membase + offset);
+static void mem_serial_out(struct uart_port *p, int offset, int value)
+{
+       offset = map_8250_out_reg(p, offset) << p->regshift;
+       writeb(value, p->membase + offset);
+}
+
+static void mem32_serial_out(struct uart_port *p, int offset, int value)
+{
+       offset = map_8250_out_reg(p, offset) << p->regshift;
+       writel(value, p->membase + offset);
+}
+
+static unsigned int mem32_serial_in(struct uart_port *p, int offset)
+{
+       offset = map_8250_in_reg(p, offset) << p->regshift;
+       return readl(p->membase + offset);
+}
 
 #ifdef CONFIG_SERIAL_8250_AU1X00
-       case UPIO_AU:
-               return __raw_readl(up->port.membase + offset);
+static unsigned int au_serial_in(struct uart_port *p, int offset)
+{
+       offset = map_8250_in_reg(p, offset) << p->regshift;
+       return __raw_readl(p->membase + offset);
+}
+
+static void au_serial_out(struct uart_port *p, int offset, int value)
+{
+       offset = map_8250_out_reg(p, offset) << p->regshift;
+       __raw_writel(value, p->membase + offset);
+}
 #endif
 
-       case UPIO_TSI:
-               if (offset == UART_IIR) {
-                       tmp = readl(up->port.membase + (UART_IIR & ~3));
-                       return (tmp >> 16) & 0xff; /* UART_IIR % 4 == 2 */
-               } else
-                       return readb(up->port.membase + offset);
+static unsigned int tsi_serial_in(struct uart_port *p, int offset)
+{
+       unsigned int tmp;
+       offset = map_8250_in_reg(p, offset) << p->regshift;
+       if (offset == UART_IIR) {
+               tmp = readl(p->membase + (UART_IIR & ~3));
+               return (tmp >> 16) & 0xff; /* UART_IIR % 4 == 2 */
+       } else
+               return readb(p->membase + offset);
+}
 
-       default:
-               return inb(up->port.iobase + offset);
-       }
+static void tsi_serial_out(struct uart_port *p, int offset, int value)
+{
+       offset = map_8250_out_reg(p, offset) << p->regshift;
+       if (!((offset == UART_IER) && (value & UART_IER_UUE)))
+               writeb(value, p->membase + offset);
 }
 
-static void
-serial_out(struct uart_8250_port *up, int offset, int value)
+static void dwapb_serial_out(struct uart_port *p, int offset, int value)
 {
-       /* Save the offset before it's remapped */
        int save_offset = offset;
-       offset = map_8250_out_reg(up, offset) << up->port.regshift;
+       offset = map_8250_out_reg(p, offset) << p->regshift;
+       /* Save the LCR value so it can be re-written when a
+        * Busy Detect interrupt occurs. */
+       if (save_offset == UART_LCR) {
+               struct uart_8250_port *up = (struct uart_8250_port *)p;
+               up->lcr = value;
+       }
+       writeb(value, p->membase + offset);
+       /* Read the IER to ensure any interrupt is cleared before
+        * returning from ISR. */
+       if (save_offset == UART_TX || save_offset == UART_IER)
+               value = p->serial_in(p, UART_IER);
+}
 
-       switch (up->port.iotype) {
+static unsigned int io_serial_in(struct uart_port *p, int offset)
+{
+       offset = map_8250_in_reg(p, offset) << p->regshift;
+       return inb(p->iobase + offset);
+}
+
+static void io_serial_out(struct uart_port *p, int offset, int value)
+{
+       offset = map_8250_out_reg(p, offset) << p->regshift;
+       outb(value, p->iobase + offset);
+}
+
+static void set_io_from_upio(struct uart_port *p)
+{
+       switch (p->iotype) {
        case UPIO_HUB6:
-               outb(up->port.hub6 - 1 + offset, up->port.iobase);
-               outb(value, up->port.iobase + 1);
+               p->serial_in = hub6_serial_in;
+               p->serial_out = hub6_serial_out;
                break;
 
        case UPIO_MEM:
-               writeb(value, up->port.membase + offset);
+               p->serial_in = mem_serial_in;
+               p->serial_out = mem_serial_out;
                break;
 
        case UPIO_RM9000:
        case UPIO_MEM32:
-               writel(value, up->port.membase + offset);
+               p->serial_in = mem32_serial_in;
+               p->serial_out = mem32_serial_out;
                break;
 
 #ifdef CONFIG_SERIAL_8250_AU1X00
        case UPIO_AU:
-               __raw_writel(value, up->port.membase + offset);
+               p->serial_in = au_serial_in;
+               p->serial_out = au_serial_out;
                break;
 #endif
        case UPIO_TSI:
-               if (!((offset == UART_IER) && (value & UART_IER_UUE)))
-                       writeb(value, up->port.membase + offset);
+               p->serial_in = tsi_serial_in;
+               p->serial_out = tsi_serial_out;
                break;
 
        case UPIO_DWAPB:
-               /* Save the LCR value so it can be re-written when a
-                * Busy Detect interrupt occurs. */
-               if (save_offset == UART_LCR)
-                       up->lcr = value;
-               writeb(value, up->port.membase + offset);
-               /* Read the IER to ensure any interrupt is cleared before
-                * returning from ISR. */
-               if (save_offset == UART_TX || save_offset == UART_IER)
-                       value = serial_in(up, UART_IER);
+               p->serial_in = mem_serial_in;
+               p->serial_out = dwapb_serial_out;
                break;
 
        default:
-               outb(value, up->port.iobase + offset);
+               p->serial_in = io_serial_in;
+               p->serial_out = io_serial_out;
+               break;
        }
 }
 
 static void
 serial_out_sync(struct uart_8250_port *up, int offset, int value)
 {
-       switch (up->port.iotype) {
+       struct uart_port *p = &up->port;
+       switch (p->iotype) {
        case UPIO_MEM:
        case UPIO_MEM32:
 #ifdef CONFIG_SERIAL_8250_AU1X00
        case UPIO_AU:
 #endif
        case UPIO_DWAPB:
-               serial_out(up, offset, value);
-               serial_in(up, UART_LCR);        /* safe, no side-effects */
+               p->serial_out(p, offset, value);
+               p->serial_in(p, UART_LCR);      /* safe, no side-effects */
                break;
        default:
-               serial_out(up, offset, value);
+               p->serial_out(p, offset, value);
        }
 }
 
+#define serial_in(up, offset)          \
+       (up->port.serial_in(&(up)->port, (offset)))
+#define serial_out(up, offset, value)  \
+       (up->port.serial_out(&(up)->port, (offset), (value)))
 /*
  * We used to support using pause I/O for certain machines.  We
  * haven't supported this for a while, but just in case it's badly
@@ -2576,6 +2645,7 @@ static void __init serial8250_isa_init_ports(void)
                up->port.membase  = old_serial_port[i].iomem_base;
                up->port.iotype   = old_serial_port[i].io_type;
                up->port.regshift = old_serial_port[i].iomem_reg_shift;
+               set_io_from_upio(&up->port);
                if (share_irqs)
                        up->port.flags |= UPF_SHARE_IRQ;
        }
@@ -2752,12 +2822,30 @@ static struct uart_driver serial8250_reg = {
  */
 int __init early_serial_setup(struct uart_port *port)
 {
+       struct uart_port *p;
+
        if (port->line >= ARRAY_SIZE(serial8250_ports))
                return -ENODEV;
 
        serial8250_isa_init_ports();
-       serial8250_ports[port->line].port       = *port;
-       serial8250_ports[port->line].port.ops   = &serial8250_pops;
+       p = &serial8250_ports[port->line].port;
+       p->iobase       = port->iobase;
+       p->membase      = port->membase;
+       p->irq          = port->irq;
+       p->uartclk      = port->uartclk;
+       p->fifosize     = port->fifosize;
+       p->regshift     = port->regshift;
+       p->iotype       = port->iotype;
+       p->flags        = port->flags;
+       p->mapbase      = port->mapbase;
+       p->private_data = port->private_data;
+
+       set_io_from_upio(p);
+       if (port->serial_in)
+               p->serial_in = port->serial_in;
+       if (port->serial_out)
+               p->serial_out = port->serial_out;
+
        return 0;
 }
 
@@ -2822,6 +2910,9 @@ static int __devinit serial8250_probe(struct platform_device *dev)
                port.mapbase            = p->mapbase;
                port.hub6               = p->hub6;
                port.private_data       = p->private_data;
+               port.type               = p->type;
+               port.serial_in          = p->serial_in;
+               port.serial_out         = p->serial_out;
                port.dev                = &dev->dev;
                if (share_irqs)
                        port.flags |= UPF_SHARE_IRQ;
@@ -2976,6 +3067,20 @@ int serial8250_register_port(struct uart_port *port)
                if (port->dev)
                        uart->port.dev = port->dev;
 
+               if (port->flags & UPF_FIXED_TYPE) {
+                       uart->port.type = port->type;
+                       uart->port.fifosize = uart_config[port->type].fifo_size;
+                       uart->capabilities = uart_config[port->type].flags;
+                       uart->tx_loadsz = uart_config[port->type].tx_loadsz;
+               }
+
+               set_io_from_upio(&uart->port);
+               /* Possibly override default I/O functions.  */
+               if (port->serial_in)
+                       uart->port.serial_in = port->serial_in;
+               if (port->serial_out)
+                       uart->port.serial_out = port->serial_out;
+
                ret = uart_add_one_port(&serial8250_reg, &uart->port);
                if (ret == 0)
                        ret = uart->port.line;
index 5450a0e5ecdb37940e13cd47d62c56e3be6e3042..c088146b7513d1c0109b8ddd579ef5052d2fbe18 100644 (file)
@@ -42,7 +42,8 @@ struct pci_serial_quirk {
        u32     subvendor;
        u32     subdevice;
        int     (*init)(struct pci_dev *dev);
-       int     (*setup)(struct serial_private *, struct pciserial_board *,
+       int     (*setup)(struct serial_private *,
+                        const struct pciserial_board *,
                         struct uart_port *, int);
        void    (*exit)(struct pci_dev *dev);
 };
@@ -107,7 +108,7 @@ setup_port(struct serial_private *priv, struct uart_port *port,
  * ADDI-DATA GmbH communication cards <info@addi-data.com>
  */
 static int addidata_apci7800_setup(struct serial_private *priv,
-                               struct pciserial_board *board,
+                               const struct pciserial_board *board,
                                struct uart_port *port, int idx)
 {
        unsigned int bar = 0, offset = board->first_offset;
@@ -134,7 +135,7 @@ static int addidata_apci7800_setup(struct serial_private *priv,
  * Not that ugly ;) -- HW
  */
 static int
-afavlab_setup(struct serial_private *priv, struct pciserial_board *board,
+afavlab_setup(struct serial_private *priv, const struct pciserial_board *board,
              struct uart_port *port, int idx)
 {
        unsigned int bar, offset = board->first_offset;
@@ -188,8 +189,9 @@ static int pci_hp_diva_init(struct pci_dev *dev)
  * some serial ports are supposed to be hidden on certain models.
  */
 static int
-pci_hp_diva_setup(struct serial_private *priv, struct pciserial_board *board,
-             struct uart_port *port, int idx)
+pci_hp_diva_setup(struct serial_private *priv,
+               const struct pciserial_board *board,
+               struct uart_port *port, int idx)
 {
        unsigned int offset = board->first_offset;
        unsigned int bar = FL_GET_BASE(board->flags);
@@ -306,7 +308,7 @@ static void __devexit pci_plx9050_exit(struct pci_dev *dev)
 
 /* SBS Technologies Inc. PMC-OCTPRO and P-OCTAL cards */
 static int
-sbs_setup(struct serial_private *priv, struct pciserial_board *board,
+sbs_setup(struct serial_private *priv, const struct pciserial_board *board,
                struct uart_port *port, int idx)
 {
        unsigned int bar, offset = board->first_offset;
@@ -463,7 +465,7 @@ static int pci_siig_init(struct pci_dev *dev)
 }
 
 static int pci_siig_setup(struct serial_private *priv,
-                         struct pciserial_board *board,
+                         const struct pciserial_board *board,
                          struct uart_port *port, int idx)
 {
        unsigned int bar = FL_GET_BASE(board->flags) + idx, offset = 0;
@@ -534,7 +536,8 @@ static int pci_timedia_init(struct pci_dev *dev)
  * Ugh, this is ugly as all hell --- TYT
  */
 static int
-pci_timedia_setup(struct serial_private *priv, struct pciserial_board *board,
+pci_timedia_setup(struct serial_private *priv,
+                 const struct pciserial_board *board,
                  struct uart_port *port, int idx)
 {
        unsigned int bar = 0, offset = board->first_offset;
@@ -568,7 +571,7 @@ pci_timedia_setup(struct serial_private *priv, struct pciserial_board *board,
  */
 static int
 titan_400l_800l_setup(struct serial_private *priv,
-                     struct pciserial_board *board,
+                     const struct pciserial_board *board,
                      struct uart_port *port, int idx)
 {
        unsigned int bar, offset = board->first_offset;
@@ -737,8 +740,41 @@ static void __devexit pci_ite887x_exit(struct pci_dev *dev)
        release_region(ioport, ITE_887x_IOSIZE);
 }
 
+/*
+ * Oxford Semiconductor Inc.
+ * Check that device is part of the Tornado range of devices, then determine
+ * the number of ports available on the device.
+ */
+static int pci_oxsemi_tornado_init(struct pci_dev *dev)
+{
+       u8 __iomem *p;
+       unsigned long deviceID;
+       unsigned int  number_uarts = 0;
+
+       /* OxSemi Tornado devices are all 0xCxxx */
+       if (dev->vendor == PCI_VENDOR_ID_OXSEMI &&
+           (dev->device & 0xF000) != 0xC000)
+               return 0;
+
+       p = pci_iomap(dev, 0, 5);
+       if (p == NULL)
+               return -ENOMEM;
+
+       deviceID = ioread32(p);
+       /* Tornado device */
+       if (deviceID == 0x07000200) {
+               number_uarts = ioread8(p + 4);
+               printk(KERN_DEBUG
+                       "%d ports detected on Oxford PCI Express device\n",
+                                                               number_uarts);
+       }
+       pci_iounmap(dev, p);
+       return number_uarts;
+}
+
 static int
-pci_default_setup(struct serial_private *priv, struct pciserial_board *board,
+pci_default_setup(struct serial_private *priv,
+                 const struct pciserial_board *board,
                  struct uart_port *port, int idx)
 {
        unsigned int bar, offset = board->first_offset, maxnr;
@@ -1017,6 +1053,25 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
                .init           = pci_netmos_init,
                .setup          = pci_default_setup,
        },
+       /*
+        * For Oxford Semiconductor and Mainpine
+        */
+       {
+               .vendor         = PCI_VENDOR_ID_OXSEMI,
+               .device         = PCI_ANY_ID,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_oxsemi_tornado_init,
+               .setup          = pci_default_setup,
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_MAINPINE,
+               .device         = PCI_ANY_ID,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_oxsemi_tornado_init,
+               .setup          = pci_default_setup,
+       },
        /*
         * Default "match everything" terminator entry
         */
@@ -1048,7 +1103,7 @@ static struct pci_serial_quirk *find_quirk(struct pci_dev *dev)
 }
 
 static inline int get_pci_irq(struct pci_dev *dev,
-                               struct pciserial_board *board)
+                               const struct pciserial_board *board)
 {
        if (board->flags & FL_NOIRQ)
                return 0;
@@ -1843,8 +1898,8 @@ serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board)
 }
 
 static inline int
-serial_pci_matches(struct pciserial_board *board,
-                  struct pciserial_board *guessed)
+serial_pci_matches(const struct pciserial_board *board,
+                  const struct pciserial_board *guessed)
 {
        return
            board->num_ports == guessed->num_ports &&
@@ -1854,54 +1909,14 @@ serial_pci_matches(struct pciserial_board *board,
            board->first_offset == guessed->first_offset;
 }
 
-/*
- * Oxford Semiconductor Inc.
- * Check that device is part of the Tornado range of devices, then determine
- * the number of ports available on the device.
- */
-static int pci_oxsemi_tornado_init(struct pci_dev *dev, struct pciserial_board *board)
-{
-       u8 __iomem *p;
-       unsigned long deviceID;
-       unsigned int  number_uarts;
-
-       /* OxSemi Tornado devices are all 0xCxxx */
-       if (dev->vendor == PCI_VENDOR_ID_OXSEMI &&
-           (dev->device & 0xF000) != 0xC000)
-               return 0;
-
-       p = pci_iomap(dev, 0, 5);
-       if (p == NULL)
-               return -ENOMEM;
-
-       deviceID = ioread32(p);
-       /* Tornado device */
-       if (deviceID == 0x07000200) {
-               number_uarts = ioread8(p + 4);
-               board->num_ports = number_uarts;
-               printk(KERN_DEBUG
-                       "%d ports detected on Oxford PCI Express device\n",
-                                                               number_uarts);
-       }
-       pci_iounmap(dev, p);
-       return 0;
-}
-
 struct serial_private *
-pciserial_init_ports(struct pci_dev *dev, struct pciserial_board *board)
+pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board)
 {
        struct uart_port serial_port;
        struct serial_private *priv;
        struct pci_serial_quirk *quirk;
        int rc, nr_ports, i;
 
-       /*
-        * Find number of ports on board
-        */
-       if (dev->vendor == PCI_VENDOR_ID_OXSEMI ||
-           dev->vendor == PCI_VENDOR_ID_MAINPINE)
-               pci_oxsemi_tornado_init(dev, board);
-
        nr_ports = board->num_ports;
 
        /*
@@ -2028,7 +2043,8 @@ static int __devinit
 pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
 {
        struct serial_private *priv;
-       struct pciserial_board *board, tmp;
+       const struct pciserial_board *board;
+       struct pciserial_board tmp;
        int rc;
 
        if (ent->driver_data >= ARRAY_SIZE(pci_boards)) {
@@ -2055,7 +2071,7 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
                 * We matched one of our class entries.  Try to
                 * determine the parameters of this board.
                 */
-               rc = serial_pci_guess_board(dev, board);
+               rc = serial_pci_guess_board(dev, &tmp);
                if (rc)
                        goto disable;
        } else {
@@ -2271,6 +2287,9 @@ static struct pci_device_id serial_pci_tbl[] = {
        {       PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM8,
                PCI_ANY_ID, PCI_ANY_ID, 0, 0,
                pbn_b2_8_115200 },
+       {       PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_7803,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_8_460800 },
        {       PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM8,
                PCI_ANY_ID, PCI_ANY_ID, 0, 0,
                pbn_b2_8_115200 },
@@ -2371,6 +2390,9 @@ static struct pci_device_id serial_pci_tbl[] = {
                 * www.ussg.iu.edu/hypermail/linux/kernel/0303.1/0516.html).
                 * For now just used the hex ID 0x950a.
                 */
+       {       PCI_VENDOR_ID_OXSEMI, 0x950a,
+               PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_DUAL_SERIAL, 0, 0,
+               pbn_b0_2_115200 },
        {       PCI_VENDOR_ID_OXSEMI, 0x950a,
                PCI_ANY_ID, PCI_ANY_ID, 0, 0,
                pbn_b0_2_1130000 },
index 569f0e2476c690259e6234911db7c33c4998c4b9..318d69dce8e1351f72cf1c100c0eba4b508cf54f 100644 (file)
@@ -22,7 +22,8 @@
 #include <linux/tty_flip.h>
 #include <linux/serial_core.h>
 
-#ifdef CONFIG_KGDB_UART
+#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
+       defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
 #include <linux/kgdb.h>
 #include <asm/irq_regs.h>
 #endif
 static struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS];
 static int nr_active_ports = ARRAY_SIZE(bfin_serial_resource);
 
+#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
+       defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
+
+# ifndef CONFIG_SERIAL_BFIN_PIO
+#  error KGDB only support UART in PIO mode.
+# endif
+
+static int kgdboc_port_line;
+static int kgdboc_break_enabled;
+#endif
 /*
  * Setup for console. Argument comes from the menuconfig
  */
@@ -62,13 +73,17 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart);
 
 static void bfin_serial_mctrl_check(struct bfin_serial_port *uart);
 
+static void bfin_serial_reset_irda(struct uart_port *port);
+
 /*
  * interrupts are disabled on entry
  */
 static void bfin_serial_stop_tx(struct uart_port *port)
 {
        struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+#ifdef CONFIG_SERIAL_BFIN_DMA
        struct circ_buf *xmit = &uart->port.info->xmit;
+#endif
 
        while (!(UART_GET_LSR(uart) & TEMT))
                cpu_relax();
@@ -94,6 +109,14 @@ static void bfin_serial_stop_tx(struct uart_port *port)
 static void bfin_serial_start_tx(struct uart_port *port)
 {
        struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+       struct tty_struct *tty = uart->port.info->port.tty;
+
+       /*
+        * To avoid losting RX interrupt, we reset IR function
+        * before sending data.
+        */
+       if (tty->termios->c_line == N_IRDA)
+               bfin_serial_reset_irda(port);
 
 #ifdef CONFIG_SERIAL_BFIN_DMA
        if (uart->tx_done)
@@ -110,9 +133,7 @@ static void bfin_serial_start_tx(struct uart_port *port)
 static void bfin_serial_stop_rx(struct uart_port *port)
 {
        struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-#ifdef CONFIG_KGDB_UART
-       if (uart->port.line != CONFIG_KGDB_UART_PORT)
-#endif
+
        UART_CLEAR_IER(uart, ERBFI);
 }
 
@@ -123,49 +144,6 @@ static void bfin_serial_enable_ms(struct uart_port *port)
 {
 }
 
-#ifdef CONFIG_KGDB_UART
-static int kgdb_entry_state;
-
-void kgdb_put_debug_char(int chr)
-{
-       struct bfin_serial_port *uart;
-
-       if (CONFIG_KGDB_UART_PORT < 0
-               || CONFIG_KGDB_UART_PORT >= BFIN_UART_NR_PORTS)
-               uart = &bfin_serial_ports[0];
-       else
-               uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT];
-
-       while (!(UART_GET_LSR(uart) & THRE)) {
-               SSYNC();
-       }
-
-       UART_CLEAR_DLAB(uart);
-       UART_PUT_CHAR(uart, (unsigned char)chr);
-       SSYNC();
-}
-
-int kgdb_get_debug_char(void)
-{
-       struct bfin_serial_port *uart;
-       unsigned char chr;
-
-       if (CONFIG_KGDB_UART_PORT < 0
-               || CONFIG_KGDB_UART_PORT >= BFIN_UART_NR_PORTS)
-               uart = &bfin_serial_ports[0];
-       else
-               uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT];
-
-       while(!(UART_GET_LSR(uart) & DR)) {
-               SSYNC();
-       }
-       UART_CLEAR_DLAB(uart);
-       chr = UART_GET_CHAR(uart);
-       SSYNC();
-
-       return chr;
-}
-#endif
 
 #if ANOMALY_05000363 && defined(CONFIG_SERIAL_BFIN_PIO)
 # define UART_GET_ANOMALY_THRESHOLD(uart)    ((uart)->anomaly_threshold)
@@ -178,7 +156,7 @@ int kgdb_get_debug_char(void)
 #ifdef CONFIG_SERIAL_BFIN_PIO
 static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
 {
-       struct tty_struct *tty = uart->port.info->port.tty;
+       struct tty_struct *tty = NULL;
        unsigned int status, ch, flg;
        static struct timeval anomaly_start = { .tv_sec = 0 };
 
@@ -188,27 +166,18 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
        ch = UART_GET_CHAR(uart);
        uart->port.icount.rx++;
 
-#ifdef CONFIG_KGDB_UART
-       if (uart->port.line == CONFIG_KGDB_UART_PORT) {
-               struct pt_regs *regs = get_irq_regs();
-               if (uart->port.cons->index == CONFIG_KGDB_UART_PORT && ch == 0x1) { /* Ctrl + A */
-                       kgdb_breakkey_pressed(regs);
-                       return;
-               } else if (kgdb_entry_state == 0 && ch == '$') {/* connection from KGDB */
-                       kgdb_entry_state = 1;
-               } else if (kgdb_entry_state == 1 && ch == 'q') {
-                       kgdb_entry_state = 0;
-                       kgdb_breakkey_pressed(regs);
-                       return;
-               } else if (ch == 0x3) {/* Ctrl + C */
-                       kgdb_entry_state = 0;
-                       kgdb_breakkey_pressed(regs);
+#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
+       defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
+       if (kgdb_connected && kgdboc_port_line == uart->port.line)
+               if (ch == 0x3) {/* Ctrl + C */
+                       kgdb_breakpoint();
                        return;
-               } else {
-                       kgdb_entry_state = 0;
                }
-       }
+
+       if (!uart->port.info || !uart->port.info->tty)
+               return;
 #endif
+       tty = uart->port.info->tty;
 
        if (ANOMALY_05000363) {
                /* The BF533 (and BF561) family of processors have a nice anomaly
@@ -250,6 +219,7 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
                        return;
 
  known_good_char:
+                       status &= ~BI;
                        anomaly_start.tv_sec = 0;
                }
        }
@@ -445,7 +415,9 @@ static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart)
 
 void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart)
 {
-       int x_pos, pos;
+       int x_pos, pos, flags;
+
+       spin_lock_irqsave(&uart->port.lock, flags);
 
        uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel);
        x_pos = get_dma_curr_xcount(uart->rx_dma_channel);
@@ -463,6 +435,8 @@ void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart)
                uart->rx_dma_buf.tail = uart->rx_dma_buf.head;
        }
 
+       spin_unlock_irqrestore(&uart->port.lock, flags);
+
        mod_timer(&(uart->rx_dma_timer), jiffies + DMA_RX_FLUSH_JIFFIES);
 }
 
@@ -497,10 +471,9 @@ static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id)
        spin_lock(&uart->port.lock);
        irqstat = get_dma_curr_irqstat(uart->rx_dma_channel);
        clear_dma_irqstat(uart->rx_dma_channel);
+       bfin_serial_dma_rx_chars(uart);
        spin_unlock(&uart->port.lock);
 
-       mod_timer(&(uart->rx_dma_timer), jiffies);
-
        return IRQ_HANDLED;
 }
 #endif
@@ -630,16 +603,16 @@ static int bfin_serial_startup(struct uart_port *port)
        uart->rx_dma_timer.expires = jiffies + DMA_RX_FLUSH_JIFFIES;
        add_timer(&(uart->rx_dma_timer));
 #else
+#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
+       defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
+       if (kgdboc_port_line == uart->port.line && kgdboc_break_enabled)
+               kgdboc_break_enabled = 0;
+       else {
+# endif
        if (request_irq(uart->port.irq, bfin_serial_rx_int, IRQF_DISABLED,
             "BFIN_UART_RX", uart)) {
-# ifdef        CONFIG_KGDB_UART
-               if (uart->port.line != CONFIG_KGDB_UART_PORT) {
-# endif
                printk(KERN_NOTICE "Unable to attach BlackFin UART RX interrupt\n");
                return -EBUSY;
-# ifdef        CONFIG_KGDB_UART
-               }
-# endif
        }
 
        if (request_irq
@@ -685,6 +658,10 @@ static int bfin_serial_startup(struct uart_port *port)
                }
        }
 # endif
+#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
+       defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
+       }
+# endif
 #endif
        UART_SET_IER(uart, ERBFI);
        return 0;
@@ -715,9 +692,6 @@ static void bfin_serial_shutdown(struct uart_port *port)
        default:
                break;
        };
-#endif
-#ifdef CONFIG_KGDB_UART
-       if (uart->port.line != CONFIG_KGDB_UART_PORT)
 #endif
        free_irq(uart->port.irq, uart);
        free_irq(uart->port.irq+1, uart);
@@ -887,6 +861,65 @@ static void bfin_serial_set_ldisc(struct uart_port *port)
        }
 }
 
+#ifdef CONFIG_CONSOLE_POLL
+static void bfin_serial_poll_put_char(struct uart_port *port, unsigned char chr)
+{
+       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+
+       while (!(UART_GET_LSR(uart) & THRE))
+               cpu_relax();
+
+       UART_CLEAR_DLAB(uart);
+       UART_PUT_CHAR(uart, (unsigned char)chr);
+}
+
+static int bfin_serial_poll_get_char(struct uart_port *port)
+{
+       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+       unsigned char chr;
+
+       while (!(UART_GET_LSR(uart) & DR))
+               cpu_relax();
+
+       UART_CLEAR_DLAB(uart);
+       chr = UART_GET_CHAR(uart);
+
+       return chr;
+}
+#endif
+
+#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
+       defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
+static void bfin_kgdboc_port_shutdown(struct uart_port *port)
+{
+       if (kgdboc_break_enabled) {
+               kgdboc_break_enabled = 0;
+               bfin_serial_shutdown(port);
+       }
+}
+
+static int bfin_kgdboc_port_startup(struct uart_port *port)
+{
+       kgdboc_port_line = port->line;
+       kgdboc_break_enabled = !bfin_serial_startup(port);
+       return 0;
+}
+#endif
+
+static void bfin_serial_reset_irda(struct uart_port *port)
+{
+       int line = port->line;
+       unsigned short val;
+
+       val = UART_GET_GCTL(&bfin_serial_ports[line]);
+       val &= ~(IREN | RPOLC);
+       UART_PUT_GCTL(&bfin_serial_ports[line], val);
+       SSYNC();
+       val |= (IREN | RPOLC);
+       UART_PUT_GCTL(&bfin_serial_ports[line], val);
+       SSYNC();
+}
+
 static struct uart_ops bfin_serial_pops = {
        .tx_empty       = bfin_serial_tx_empty,
        .set_mctrl      = bfin_serial_set_mctrl,
@@ -905,6 +938,15 @@ static struct uart_ops bfin_serial_pops = {
        .request_port   = bfin_serial_request_port,
        .config_port    = bfin_serial_config_port,
        .verify_port    = bfin_serial_verify_port,
+#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
+       defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
+       .kgdboc_port_startup    = bfin_kgdboc_port_startup,
+       .kgdboc_port_shutdown   = bfin_kgdboc_port_shutdown,
+#endif
+#ifdef CONFIG_CONSOLE_POLL
+       .poll_put_char  = bfin_serial_poll_put_char,
+       .poll_get_char  = bfin_serial_poll_get_char,
+#endif
 };
 
 static void __init bfin_serial_init_ports(void)
@@ -950,7 +992,7 @@ static void __init bfin_serial_init_ports(void)
 
 }
 
-#ifdef CONFIG_SERIAL_BFIN_CONSOLE
+#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
 /*
  * If the port was already initialised (eg, by a boot loader),
  * try to determine the current setup.
@@ -994,24 +1036,20 @@ bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud,
        }
        pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __func__, *baud, *parity, *bits);
 }
-#endif
 
-#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
 static struct uart_driver bfin_serial_reg;
 
 static int __init
 bfin_serial_console_setup(struct console *co, char *options)
 {
        struct bfin_serial_port *uart;
-# ifdef CONFIG_SERIAL_BFIN_CONSOLE
        int baud = 57600;
        int bits = 8;
        int parity = 'n';
-#  ifdef CONFIG_SERIAL_BFIN_CTSRTS
+# ifdef CONFIG_SERIAL_BFIN_CTSRTS
        int flow = 'r';
-#  else
+# else
        int flow = 'n';
-#  endif
 # endif
 
        /*
@@ -1023,16 +1061,12 @@ bfin_serial_console_setup(struct console *co, char *options)
                co->index = 0;
        uart = &bfin_serial_ports[co->index];
 
-# ifdef CONFIG_SERIAL_BFIN_CONSOLE
        if (options)
                uart_parse_options(options, &baud, &parity, &bits, &flow);
        else
                bfin_serial_console_get_options(uart, &baud, &parity, &bits);
 
        return uart_set_options(&uart->port, co, baud, parity, bits, flow);
-# else
-       return 0;
-# endif
 }
 #endif /* defined (CONFIG_SERIAL_BFIN_CONSOLE) ||
                                 defined (CONFIG_EARLY_PRINTK) */
@@ -1076,10 +1110,7 @@ static int __init bfin_serial_rs_console_init(void)
 {
        bfin_serial_init_ports();
        register_console(&bfin_serial_console);
-#ifdef CONFIG_KGDB_UART
-       kgdb_entry_state = 0;
-       init_kgdb_uart();
-#endif
+
        return 0;
 }
 console_initcall(bfin_serial_rs_console_init);
@@ -1144,7 +1175,7 @@ struct console __init *bfin_earlyserial_init(unsigned int port,
        return &bfin_early_serial_console;
 }
 
-#endif /* CONFIG_SERIAL_BFIN_CONSOLE */
+#endif /* CONFIG_EARLY_PRINTK */
 
 static struct uart_driver bfin_serial_reg = {
        .owner                  = THIS_MODULE,
@@ -1235,10 +1266,6 @@ static struct platform_driver bfin_serial_driver = {
 static int __init bfin_serial_init(void)
 {
        int ret;
-#ifdef CONFIG_KGDB_UART
-       struct bfin_serial_port *uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT];
-       struct ktermios t;
-#endif
 
        pr_info("Serial: Blackfin serial driver\n");
 
@@ -1252,21 +1279,6 @@ static int __init bfin_serial_init(void)
                        uart_unregister_driver(&bfin_serial_reg);
                }
        }
-#ifdef CONFIG_KGDB_UART
-       if (uart->port.cons->index != CONFIG_KGDB_UART_PORT) {
-               request_irq(uart->port.irq, bfin_serial_rx_int,
-                       IRQF_DISABLED, "BFIN_UART_RX", uart);
-               pr_info("Request irq for kgdb uart port\n");
-               UART_SET_IER(uart, ERBFI);
-               SSYNC();
-               t.c_cflag = CS8|B57600;
-               t.c_iflag = 0;
-               t.c_oflag = 0;
-               t.c_lflag = ICANON;
-               t.c_line = CONFIG_KGDB_UART_PORT;
-               bfin_serial_set_termios(&uart->port, &t, &t);
-       }
-#endif
        return ret;
 }
 
@@ -1276,6 +1288,7 @@ static void __exit bfin_serial_exit(void)
        uart_unregister_driver(&bfin_serial_reg);
 }
 
+
 module_init(bfin_serial_init);
 module_exit(bfin_serial_exit);
 
index dd8564d250514f44b634c66b01c1fc5e38f1791c..529c0ff7952ceca111e8db153a3794448ca3b5ae 100644 (file)
@@ -99,7 +99,7 @@ static void sport_stop_tx(struct uart_port *port);
 
 static inline void tx_one_byte(struct sport_uart_port *up, unsigned int value)
 {
-       pr_debug("%s value:%x\n", __FUNCTION__, value);
+       pr_debug("%s value:%x\n", __func__, value);
        /* Place a Start and Stop bit */
        __asm__ volatile (
                "R2 = b#01111111100;\n\t"
@@ -110,7 +110,7 @@ static inline void tx_one_byte(struct sport_uart_port *up, unsigned int value)
                :"=r"(value)
                :"0"(value)
                :"R2", "R3");
-       pr_debug("%s value:%x\n", __FUNCTION__, value);
+       pr_debug("%s value:%x\n", __func__, value);
 
        SPORT_PUT_TX(up, value);
 }
@@ -120,7 +120,7 @@ static inline unsigned int rx_one_byte(struct sport_uart_port *up)
        unsigned int value, extract;
 
        value = SPORT_GET_RX32(up);
-       pr_debug("%s value:%x\n", __FUNCTION__, value);
+       pr_debug("%s value:%x\n", __func__, value);
 
        /* Extract 8 bits data */
        __asm__ volatile (
@@ -151,12 +151,12 @@ static int sport_uart_setup(struct sport_uart_port *up, int sclk, int baud_rate)
        /* Set TCR1 and TCR2 */
        SPORT_PUT_TCR1(up, (LTFS | ITFS | TFSR | TLSBIT | ITCLK));
        SPORT_PUT_TCR2(up, 10);
-       pr_debug("%s TCR1:%x, TCR2:%x\n", __FUNCTION__, SPORT_GET_TCR1(up), SPORT_GET_TCR2(up));
+       pr_debug("%s TCR1:%x, TCR2:%x\n", __func__, SPORT_GET_TCR1(up), SPORT_GET_TCR2(up));
 
        /* Set RCR1 and RCR2 */
        SPORT_PUT_RCR1(up, (RCKFE | LARFS | LRFS | RFSR | IRCLK));
        SPORT_PUT_RCR2(up, 28);
-       pr_debug("%s RCR1:%x, RCR2:%x\n", __FUNCTION__, SPORT_GET_RCR1(up), SPORT_GET_RCR2(up));
+       pr_debug("%s RCR1:%x, RCR2:%x\n", __func__, SPORT_GET_RCR1(up), SPORT_GET_RCR2(up));
 
        tclkdiv = sclk/(2 * baud_rate) - 1;
        tfsdiv = 12;
@@ -166,7 +166,7 @@ static int sport_uart_setup(struct sport_uart_port *up, int sclk, int baud_rate)
        SPORT_PUT_RCLKDIV(up, rclkdiv);
        SSYNC();
        pr_debug("%s sclk:%d, baud_rate:%d, tclkdiv:%d, tfsdiv:%d, rclkdiv:%d\n",
-                       __FUNCTION__, sclk, baud_rate, tclkdiv, tfsdiv, rclkdiv);
+                       __func__, sclk, baud_rate, tclkdiv, tfsdiv, rclkdiv);
 
        return 0;
 }
@@ -231,7 +231,7 @@ static int sport_startup(struct uart_port *port)
        char buffer[20];
        int retval;
 
-       pr_debug("%s enter\n", __FUNCTION__);
+       pr_debug("%s enter\n", __func__);
        memset(buffer, 20, '\0');
        snprintf(buffer, 20, "%s rx", up->name);
        retval = request_irq(up->rx_irq, sport_uart_rx_irq, IRQF_SAMPLE_RANDOM, buffer, up);
@@ -320,7 +320,7 @@ static unsigned int sport_tx_empty(struct uart_port *port)
        unsigned int stat;
 
        stat = SPORT_GET_STAT(up);
-       pr_debug("%s stat:%04x\n", __FUNCTION__, stat);
+       pr_debug("%s stat:%04x\n", __func__, stat);
        if (stat & TXHRE) {
                return TIOCSER_TEMT;
        } else
@@ -329,13 +329,13 @@ static unsigned int sport_tx_empty(struct uart_port *port)
 
 static unsigned int sport_get_mctrl(struct uart_port *port)
 {
-       pr_debug("%s enter\n", __FUNCTION__);
+       pr_debug("%s enter\n", __func__);
        return (TIOCM_CTS | TIOCM_CD | TIOCM_DSR);
 }
 
 static void sport_set_mctrl(struct uart_port *port, unsigned int mctrl)
 {
-       pr_debug("%s enter\n", __FUNCTION__);
+       pr_debug("%s enter\n", __func__);
 }
 
 static void sport_stop_tx(struct uart_port *port)
@@ -343,7 +343,7 @@ static void sport_stop_tx(struct uart_port *port)
        struct sport_uart_port *up = (struct sport_uart_port *)port;
        unsigned int stat;
 
-       pr_debug("%s enter\n", __FUNCTION__);
+       pr_debug("%s enter\n", __func__);
 
        stat = SPORT_GET_STAT(up);
        while(!(stat & TXHRE)) {
@@ -366,21 +366,21 @@ static void sport_start_tx(struct uart_port *port)
 {
        struct sport_uart_port *up = (struct sport_uart_port *)port;
 
-       pr_debug("%s enter\n", __FUNCTION__);
+       pr_debug("%s enter\n", __func__);
        /* Write data into SPORT FIFO before enable SPROT to transmit */
        sport_uart_tx_chars(up);
 
        /* Enable transmit, then an interrupt will generated */
        SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) | TSPEN));
        SSYNC();
-       pr_debug("%s exit\n", __FUNCTION__);
+       pr_debug("%s exit\n", __func__);
 }
 
 static void sport_stop_rx(struct uart_port *port)
 {
        struct sport_uart_port *up = (struct sport_uart_port *)port;
 
-       pr_debug("%s enter\n", __FUNCTION__);
+       pr_debug("%s enter\n", __func__);
        /* Disable sport to stop rx */
        SPORT_PUT_RCR1(up, (SPORT_GET_RCR1(up) & ~RSPEN));
        SSYNC();
@@ -388,19 +388,19 @@ static void sport_stop_rx(struct uart_port *port)
 
 static void sport_enable_ms(struct uart_port *port)
 {
-       pr_debug("%s enter\n", __FUNCTION__);
+       pr_debug("%s enter\n", __func__);
 }
 
 static void sport_break_ctl(struct uart_port *port, int break_state)
 {
-       pr_debug("%s enter\n", __FUNCTION__);
+       pr_debug("%s enter\n", __func__);
 }
 
 static void sport_shutdown(struct uart_port *port)
 {
        struct sport_uart_port *up = (struct sport_uart_port *)port;
 
-       pr_debug("%s enter\n", __FUNCTION__);
+       pr_debug("%s enter\n", __func__);
 
        /* Disable sport */
        SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) & ~TSPEN));
@@ -421,7 +421,7 @@ static void sport_shutdown(struct uart_port *port)
 static void sport_set_termios(struct uart_port *port,
                struct termios *termios, struct termios *old)
 {
-       pr_debug("%s enter, c_cflag:%08x\n", __FUNCTION__, termios->c_cflag);
+       pr_debug("%s enter, c_cflag:%08x\n", __func__, termios->c_cflag);
        uart_update_timeout(port, CS8 ,port->uartclk);
 }
 
@@ -429,18 +429,18 @@ static const char *sport_type(struct uart_port *port)
 {
        struct sport_uart_port *up = (struct sport_uart_port *)port;
 
-       pr_debug("%s enter\n", __FUNCTION__);
+       pr_debug("%s enter\n", __func__);
        return up->name;
 }
 
 static void sport_release_port(struct uart_port *port)
 {
-       pr_debug("%s enter\n", __FUNCTION__);
+       pr_debug("%s enter\n", __func__);
 }
 
 static int sport_request_port(struct uart_port *port)
 {
-       pr_debug("%s enter\n", __FUNCTION__);
+       pr_debug("%s enter\n", __func__);
        return 0;
 }
 
@@ -448,13 +448,13 @@ static void sport_config_port(struct uart_port *port, int flags)
 {
        struct sport_uart_port *up = (struct sport_uart_port *)port;
 
-       pr_debug("%s enter\n", __FUNCTION__);
+       pr_debug("%s enter\n", __func__);
        up->port.type = PORT_BFIN_SPORT;
 }
 
 static int sport_verify_port(struct uart_port *port, struct serial_struct *ser)
 {
-       pr_debug("%s enter\n", __FUNCTION__);
+       pr_debug("%s enter\n", __func__);
        return 0;
 }
 
@@ -527,7 +527,7 @@ static int sport_uart_suspend(struct platform_device *dev, pm_message_t state)
 {
        struct sport_uart_port *sport = platform_get_drvdata(dev);
 
-       pr_debug("%s enter\n", __FUNCTION__);
+       pr_debug("%s enter\n", __func__);
        if (sport)
                uart_suspend_port(&sport_uart_reg, &sport->port);
 
@@ -538,7 +538,7 @@ static int sport_uart_resume(struct platform_device *dev)
 {
        struct sport_uart_port *sport = platform_get_drvdata(dev);
 
-       pr_debug("%s enter\n", __FUNCTION__);
+       pr_debug("%s enter\n", __func__);
        if (sport)
                uart_resume_port(&sport_uart_reg, &sport->port);
 
@@ -547,7 +547,7 @@ static int sport_uart_resume(struct platform_device *dev)
 
 static int sport_uart_probe(struct platform_device *dev)
 {
-       pr_debug("%s enter\n", __FUNCTION__);
+       pr_debug("%s enter\n", __func__);
        sport_uart_ports[dev->id].port.dev = &dev->dev;
        uart_add_one_port(&sport_uart_reg, &sport_uart_ports[dev->id].port);
        platform_set_drvdata(dev, &sport_uart_ports[dev->id]);
@@ -559,7 +559,7 @@ static int sport_uart_remove(struct platform_device *dev)
 {
        struct sport_uart_port *sport = platform_get_drvdata(dev);
 
-       pr_debug("%s enter\n", __FUNCTION__);
+       pr_debug("%s enter\n", __func__);
        platform_set_drvdata(dev, NULL);
 
        if (sport)
@@ -582,7 +582,7 @@ static int __init sport_uart_init(void)
 {
        int ret;
 
-       pr_debug("%s enter\n", __FUNCTION__);
+       pr_debug("%s enter\n", __func__);
        ret = uart_register_driver(&sport_uart_reg);
        if (ret != 0) {
                printk(KERN_ERR "Failed to register %s:%d\n",
@@ -597,13 +597,13 @@ static int __init sport_uart_init(void)
        }
 
 
-       pr_debug("%s exit\n", __FUNCTION__);
+       pr_debug("%s exit\n", __func__);
        return ret;
 }
 
 static void __exit sport_uart_exit(void)
 {
-       pr_debug("%s enter\n", __FUNCTION__);
+       pr_debug("%s enter\n", __func__);
        platform_driver_unregister(&sport_uart_driver);
        uart_unregister_driver(&sport_uart_reg);
 }
index a697914ae3d043e086d267338450e9ae907baa33..3547558d2caf87290d81505c0181e353029ddd6b 100644 (file)
@@ -272,7 +272,7 @@ static void jsm_tty_close(struct uart_port *port)
        jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev, "start\n");
 
        bd = channel->ch_bd;
-       ts = channel->uart_port.info->port.tty->termios;
+       ts = port->info->port.tty->termios;
 
        channel->ch_flags &= ~(CH_STOPI);
 
index 874786a11fe9977b98d4de8c540669111170e7ee..dc68b7e0c93049d9fe360b587fafe5a94230bfea 100644 (file)
@@ -50,7 +50,7 @@ static struct lock_class_key port_lock_key;
 
 #define HIGH_BITS_OFFSET       ((sizeof(long)-sizeof(int))*8)
 
-#define uart_users(state)      ((state)->count + ((state)->info ? (state)->info->port.blocked_open : 0))
+#define uart_users(state)      ((state)->count + (state)->info.port.blocked_open)
 
 #ifdef CONFIG_SERIAL_CORE_CONSOLE
 #define uart_console(port)     ((port)->cons && (port)->cons->index == (port)->line)
@@ -94,7 +94,7 @@ static void __uart_start(struct tty_struct *tty)
        struct uart_state *state = tty->driver_data;
        struct uart_port *port = state->port;
 
-       if (!uart_circ_empty(&state->info->xmit) && state->info->xmit.buf &&
+       if (!uart_circ_empty(&state->info.xmit) && state->info.xmit.buf &&
            !tty->stopped && !tty->hw_stopped)
                port->ops->start_tx(port);
 }
@@ -113,7 +113,7 @@ static void uart_start(struct tty_struct *tty)
 static void uart_tasklet_action(unsigned long data)
 {
        struct uart_state *state = (struct uart_state *)data;
-       tty_wakeup(state->info->port.tty);
+       tty_wakeup(state->info.port.tty);
 }
 
 static inline void
@@ -139,7 +139,7 @@ uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear)
  */
 static int uart_startup(struct uart_state *state, int init_hw)
 {
-       struct uart_info *info = state->info;
+       struct uart_info *info = &state->info;
        struct uart_port *port = state->port;
        unsigned long page;
        int retval = 0;
@@ -212,14 +212,15 @@ static int uart_startup(struct uart_state *state, int init_hw)
  */
 static void uart_shutdown(struct uart_state *state)
 {
-       struct uart_info *info = state->info;
+       struct uart_info *info = &state->info;
        struct uart_port *port = state->port;
+       struct tty_struct *tty = info->port.tty;
 
        /*
         * Set the TTY IO error marker
         */
-       if (info->port.tty)
-               set_bit(TTY_IO_ERROR, &info->port.tty->flags);
+       if (tty)
+               set_bit(TTY_IO_ERROR, &tty->flags);
 
        if (info->flags & UIF_INITIALIZED) {
                info->flags &= ~UIF_INITIALIZED;
@@ -227,7 +228,7 @@ static void uart_shutdown(struct uart_state *state)
                /*
                 * Turn off DTR and RTS early.
                 */
-               if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL))
+               if (!tty || (tty->termios->c_cflag & HUPCL))
                        uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
 
                /*
@@ -427,7 +428,7 @@ EXPORT_SYMBOL(uart_get_divisor);
 static void
 uart_change_speed(struct uart_state *state, struct ktermios *old_termios)
 {
-       struct tty_struct *tty = state->info->port.tty;
+       struct tty_struct *tty = state->info.port.tty;
        struct uart_port *port = state->port;
        struct ktermios *termios;
 
@@ -444,14 +445,14 @@ uart_change_speed(struct uart_state *state, struct ktermios *old_termios)
         * Set flags based on termios cflag
         */
        if (termios->c_cflag & CRTSCTS)
-               state->info->flags |= UIF_CTS_FLOW;
+               state->info.flags |= UIF_CTS_FLOW;
        else
-               state->info->flags &= ~UIF_CTS_FLOW;
+               state->info.flags &= ~UIF_CTS_FLOW;
 
        if (termios->c_cflag & CLOCAL)
-               state->info->flags &= ~UIF_CHECK_CD;
+               state->info.flags &= ~UIF_CHECK_CD;
        else
-               state->info->flags |= UIF_CHECK_CD;
+               state->info.flags |= UIF_CHECK_CD;
 
        port->ops->set_termios(port, termios, old_termios);
 }
@@ -479,7 +480,7 @@ static int uart_put_char(struct tty_struct *tty, unsigned char ch)
 {
        struct uart_state *state = tty->driver_data;
 
-       return __uart_put_char(state->port, &state->info->xmit, ch);
+       return __uart_put_char(state->port, &state->info.xmit, ch);
 }
 
 static void uart_flush_chars(struct tty_struct *tty)
@@ -500,13 +501,13 @@ uart_write(struct tty_struct *tty, const unsigned char *buf, int count)
         * This means you called this function _after_ the port was
         * closed.  No cookie for you.
         */
-       if (!state || !state->info) {
+       if (!state) {
                WARN_ON(1);
                return -EL3HLT;
        }
 
        port = state->port;
-       circ = &state->info->xmit;
+       circ = &state->info.xmit;
 
        if (!circ->buf)
                return 0;
@@ -537,7 +538,7 @@ static int uart_write_room(struct tty_struct *tty)
        int ret;
 
        spin_lock_irqsave(&state->port->lock, flags);
-       ret = uart_circ_chars_free(&state->info->xmit);
+       ret = uart_circ_chars_free(&state->info.xmit);
        spin_unlock_irqrestore(&state->port->lock, flags);
        return ret;
 }
@@ -549,7 +550,7 @@ static int uart_chars_in_buffer(struct tty_struct *tty)
        int ret;
 
        spin_lock_irqsave(&state->port->lock, flags);
-       ret = uart_circ_chars_pending(&state->info->xmit);
+       ret = uart_circ_chars_pending(&state->info.xmit);
        spin_unlock_irqrestore(&state->port->lock, flags);
        return ret;
 }
@@ -564,7 +565,7 @@ static void uart_flush_buffer(struct tty_struct *tty)
         * This means you called this function _after_ the port was
         * closed.  No cookie for you.
         */
-       if (!state || !state->info) {
+       if (!state) {
                WARN_ON(1);
                return;
        }
@@ -573,7 +574,7 @@ static void uart_flush_buffer(struct tty_struct *tty)
        pr_debug("uart_flush_buffer(%d) called\n", tty->index);
 
        spin_lock_irqsave(&port->lock, flags);
-       uart_circ_clear(&state->info->xmit);
+       uart_circ_clear(&state->info.xmit);
        if (port->ops->flush_buffer)
                port->ops->flush_buffer(port);
        spin_unlock_irqrestore(&port->lock, flags);
@@ -837,15 +838,15 @@ static int uart_set_info(struct uart_state *state,
        state->closing_wait    = closing_wait;
        if (new_serial.xmit_fifo_size)
                port->fifosize = new_serial.xmit_fifo_size;
-       if (state->info->port.tty)
-               state->info->port.tty->low_latency =
+       if (state->info.port.tty)
+               state->info.port.tty->low_latency =
                        (port->flags & UPF_LOW_LATENCY) ? 1 : 0;
 
  check_and_exit:
        retval = 0;
        if (port->type == PORT_UNKNOWN)
                goto exit;
-       if (state->info->flags & UIF_INITIALIZED) {
+       if (state->info.flags & UIF_INITIALIZED) {
                if (((old_flags ^ port->flags) & UPF_SPD_MASK) ||
                    old_custom_divisor != port->custom_divisor) {
                        /*
@@ -858,7 +859,7 @@ static int uart_set_info(struct uart_state *state,
                                printk(KERN_NOTICE
                                       "%s sets custom speed on %s. This "
                                       "is deprecated.\n", current->comm,
-                                      tty_name(state->info->port.tty, buf));
+                                      tty_name(state->info.port.tty, buf));
                        }
                        uart_change_speed(state, NULL);
                }
@@ -889,8 +890,8 @@ static int uart_get_lsr_info(struct uart_state *state,
         * interrupt happens).
         */
        if (port->x_char ||
-           ((uart_circ_chars_pending(&state->info->xmit) > 0) &&
-            !state->info->port.tty->stopped && !state->info->port.tty->hw_stopped))
+           ((uart_circ_chars_pending(&state->info.xmit) > 0) &&
+            !state->info.port.tty->stopped && !state->info.port.tty->hw_stopped))
                result &= ~TIOCSER_TEMT;
 
        return put_user(result, value);
@@ -1017,7 +1018,7 @@ uart_wait_modem_status(struct uart_state *state, unsigned long arg)
        port->ops->enable_ms(port);
        spin_unlock_irq(&port->lock);
 
-       add_wait_queue(&state->info->delta_msr_wait, &wait);
+       add_wait_queue(&state->info.delta_msr_wait, &wait);
        for (;;) {
                spin_lock_irq(&port->lock);
                memcpy(&cnow, &port->icount, sizeof(struct uart_icount));
@@ -1045,7 +1046,7 @@ uart_wait_modem_status(struct uart_state *state, unsigned long arg)
        }
 
        current->state = TASK_RUNNING;
-       remove_wait_queue(&state->info->delta_msr_wait, &wait);
+       remove_wait_queue(&state->info.delta_msr_wait, &wait);
 
        return ret;
 }
@@ -1241,7 +1242,7 @@ static void uart_set_termios(struct tty_struct *tty,
         */
        if (!(old_termios->c_cflag & CLOCAL) &&
            (tty->termios->c_cflag & CLOCAL))
-               wake_up_interruptible(&state->info->port.open_wait);
+               wake_up_interruptible(&info->port.open_wait);
 #endif
 }
 
@@ -1303,7 +1304,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
         * At this point, we stop accepting input.  To do this, we
         * disable the receive line status interrupts.
         */
-       if (state->info->flags & UIF_INITIALIZED) {
+       if (state->info.flags & UIF_INITIALIZED) {
                unsigned long flags;
                spin_lock_irqsave(&port->lock, flags);
                port->ops->stop_rx(port);
@@ -1322,9 +1323,9 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
        tty_ldisc_flush(tty);
 
        tty->closing = 0;
-       state->info->port.tty = NULL;
+       state->info.port.tty = NULL;
 
-       if (state->info->port.blocked_open) {
+       if (state->info.port.blocked_open) {
                if (state->close_delay)
                        msleep_interruptible(state->close_delay);
        } else if (!uart_console(port)) {
@@ -1334,8 +1335,8 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
        /*
         * Wake up anyone trying to open this port.
         */
-       state->info->flags &= ~UIF_NORMAL_ACTIVE;
-       wake_up_interruptible(&state->info->port.open_wait);
+       state->info.flags &= ~UIF_NORMAL_ACTIVE;
+       wake_up_interruptible(&state->info.port.open_wait);
 
  done:
        mutex_unlock(&state->mutex);
@@ -1409,19 +1410,20 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
 static void uart_hangup(struct tty_struct *tty)
 {
        struct uart_state *state = tty->driver_data;
+       struct uart_info *info = &state->info;
 
        BUG_ON(!kernel_locked());
        pr_debug("uart_hangup(%d)\n", state->port->line);
 
        mutex_lock(&state->mutex);
-       if (state->info && state->info->flags & UIF_NORMAL_ACTIVE) {
+       if (info->flags & UIF_NORMAL_ACTIVE) {
                uart_flush_buffer(tty);
                uart_shutdown(state);
                state->count = 0;
-               state->info->flags &= ~UIF_NORMAL_ACTIVE;
-               state->info->port.tty = NULL;
-               wake_up_interruptible(&state->info->port.open_wait);
-               wake_up_interruptible(&state->info->delta_msr_wait);
+               info->flags &= ~UIF_NORMAL_ACTIVE;
+               info->port.tty = NULL;
+               wake_up_interruptible(&info->port.open_wait);
+               wake_up_interruptible(&info->delta_msr_wait);
        }
        mutex_unlock(&state->mutex);
 }
@@ -1434,7 +1436,7 @@ static void uart_hangup(struct tty_struct *tty)
  */
 static void uart_update_termios(struct uart_state *state)
 {
-       struct tty_struct *tty = state->info->port.tty;
+       struct tty_struct *tty = state->info.port.tty;
        struct uart_port *port = state->port;
 
        if (uart_console(port) && port->cons->cflag) {
@@ -1469,7 +1471,7 @@ static int
 uart_block_til_ready(struct file *filp, struct uart_state *state)
 {
        DECLARE_WAITQUEUE(wait, current);
-       struct uart_info *info = state->info;
+       struct uart_info *info = &state->info;
        struct uart_port *port = state->port;
        unsigned int mctrl;
 
@@ -1563,28 +1565,6 @@ static struct uart_state *uart_get(struct uart_driver *drv, int line)
                ret = -ENXIO;
                goto err_unlock;
        }
-
-       /* BKL: RACE HERE - LEAK */
-       /* We should move this into the uart_state structure and kill off
-          this whole complexity */
-       if (!state->info) {
-               state->info = kzalloc(sizeof(struct uart_info), GFP_KERNEL);
-               if (state->info) {
-                       init_waitqueue_head(&state->info->port.open_wait);
-                       init_waitqueue_head(&state->info->delta_msr_wait);
-
-                       /*
-                        * Link the info into the other structures.
-                        */
-                       state->port->info = state->info;
-
-                       tasklet_init(&state->info->tlet, uart_tasklet_action,
-                                    (unsigned long)state);
-               } else {
-                       ret = -ENOMEM;
-                       goto err_unlock;
-               }
-       }
        return state;
 
  err_unlock:
@@ -1641,9 +1621,10 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
         * Any failures from here onwards should not touch the count.
         */
        tty->driver_data = state;
+       state->port->info = &state->info;
        tty->low_latency = (state->port->flags & UPF_LOW_LATENCY) ? 1 : 0;
        tty->alt_speed = 0;
-       state->info->port.tty = tty;
+       state->info.port.tty = tty;
 
        /*
         * If the port is in the middle of closing, bail out now.
@@ -1676,8 +1657,8 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
        /*
         * If this is the first open to succeed, adjust things to suit.
         */
-       if (retval == 0 && !(state->info->flags & UIF_NORMAL_ACTIVE)) {
-               state->info->flags |= UIF_NORMAL_ACTIVE;
+       if (retval == 0 && !(state->info.flags & UIF_NORMAL_ACTIVE)) {
+               state->info.flags |= UIF_NORMAL_ACTIVE;
 
                uart_update_termios(state);
        }
@@ -2028,11 +2009,11 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port)
        }
        port->suspended = 1;
 
-       if (state->info && state->info->flags & UIF_INITIALIZED) {
+       if (state->info.flags & UIF_INITIALIZED) {
                const struct uart_ops *ops = port->ops;
                int tries;
 
-               state->info->flags = (state->info->flags & ~UIF_INITIALIZED)
+               state->info.flags = (state->info.flags & ~UIF_INITIALIZED)
                                     | UIF_SUSPENDED;
 
                spin_lock_irq(&port->lock);
@@ -2107,15 +2088,15 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
                /*
                 * If that's unset, use the tty termios setting.
                 */
-               if (state->info && state->info->port.tty && termios.c_cflag == 0)
-                       termios = *state->info->port.tty->termios;
+               if (state->info.port.tty && termios.c_cflag == 0)
+                       termios = *state->info.port.tty->termios;
 
                uart_change_pm(state, 0);
                port->ops->set_termios(port, &termios, NULL);
                console_start(port->cons);
        }
 
-       if (state->info && state->info->flags & UIF_SUSPENDED) {
+       if (state->info.flags & UIF_SUSPENDED) {
                const struct uart_ops *ops = port->ops;
                int ret;
 
@@ -2130,7 +2111,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
                        ops->set_mctrl(port, port->mctrl);
                        ops->start_tx(port);
                        spin_unlock_irq(&port->lock);
-                       state->info->flags |= UIF_INITIALIZED;
+                       state->info.flags |= UIF_INITIALIZED;
                } else {
                        /*
                         * Failed to resume - maybe hardware went away?
@@ -2140,7 +2121,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
                        uart_shutdown(state);
                }
 
-               state->info->flags &= ~UIF_SUSPENDED;
+               state->info.flags &= ~UIF_SUSPENDED;
        }
 
        mutex_unlock(&state->mutex);
@@ -2198,11 +2179,14 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state,
         * Now do the auto configuration stuff.  Note that config_port
         * is expected to claim the resources and map the port for us.
         */
-       flags = UART_CONFIG_TYPE;
+       flags = 0;
        if (port->flags & UPF_AUTO_IRQ)
                flags |= UART_CONFIG_IRQ;
        if (port->flags & UPF_BOOT_AUTOCONF) {
-               port->type = PORT_UNKNOWN;
+               if (!(port->flags & UPF_FIXED_TYPE)) {
+                       port->type = PORT_UNKNOWN;
+                       flags |= UART_CONFIG_TYPE;
+               }
                port->ops->config_port(port, flags);
        }
 
@@ -2383,8 +2367,12 @@ int uart_register_driver(struct uart_driver *drv)
 
                state->close_delay     = 500;   /* .5 seconds */
                state->closing_wait    = 30000; /* 30 seconds */
-
                mutex_init(&state->mutex);
+
+               tty_port_init(&state->info.port);
+               init_waitqueue_head(&state->info.delta_msr_wait);
+               tasklet_init(&state->info.tlet, uart_tasklet_action,
+                            (unsigned long)state);
        }
 
        retval = tty_register_driver(normal);
@@ -2455,7 +2443,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port)
        state->pm_state = -1;
 
        port->cons = drv->cons;
-       port->info = state->info;
+       port->info = &state->info;
 
        /*
         * If this port is a console, then the spinlock is already
@@ -2527,17 +2515,10 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port)
         */
        tty_unregister_device(drv->tty_driver, port->line);
 
-       info = state->info;
+       info = &state->info;
        if (info && info->port.tty)
                tty_vhangup(info->port.tty);
 
-       /*
-        * All users of this port should now be disconnected from
-        * this driver, and the port shut down.  We should be the
-        * only thread fiddling with this port from now on.
-        */
-       state->info = NULL;
-
        /*
         * Free the port IO and memory resources, if any.
         */
@@ -2552,10 +2533,8 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port)
        /*
         * Kill the tasklet, and free resources.
         */
-       if (info) {
+       if (info)
                tasklet_kill(&info->tlet);
-               kfree(info);
-       }
 
        state->port = NULL;
        mutex_unlock(&port_mutex);
index 5b95009d2fbb104d28065010dc857da2eace6c42..19e24045b137a2964b450afbf94cc930de3cd427 100644 (file)
@@ -241,12 +241,25 @@ static void usb_console_write(struct console *co,
        }
 }
 
+static struct tty_driver *usb_console_device(struct console *co, int *index)
+{
+       struct tty_driver **p = (struct tty_driver **)co->data;
+
+       if (!*p)
+               return NULL;
+
+       *index = co->index;
+       return *p;
+}
+
 static struct console usbcons = {
        .name =         "ttyUSB",
        .write =        usb_console_write,
+       .device =       usb_console_device,
        .setup =        usb_console_setup,
        .flags =        CON_PRINTBUFFER,
        .index =        -1,
+       .data =         &usb_serial_tty_driver,
 };
 
 void usb_serial_console_disconnect(struct usb_serial *serial)
index fb6f2933b01badb0075c285078fb6067fc7b6827..ef6cfa5a447feba817ffd8a8a819a8451db1918e 100644 (file)
@@ -1054,6 +1054,8 @@ static int set_serial_info(struct tty_struct *tty,
 
        if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
                return -EFAULT;
+
+       lock_kernel();
        old_priv = *priv;
 
        /* Do error checking and permission checking */
@@ -1069,8 +1071,10 @@ static int set_serial_info(struct tty_struct *tty,
        }
 
        if ((new_serial.baud_base != priv->baud_base) &&
-           (new_serial.baud_base < 9600))
+           (new_serial.baud_base < 9600)) {
+               unlock_kernel();
                return -EINVAL;
+       }
 
        /* Make the changes - these are privileged changes! */
 
@@ -1098,8 +1102,11 @@ check_and_exit:
             (priv->flags & ASYNC_SPD_MASK)) ||
            (((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) &&
             (old_priv.custom_divisor != priv->custom_divisor))) {
+               unlock_kernel();
                change_speed(tty, port);
        }
+       else
+               unlock_kernel();
        return 0;
 
 } /* set_serial_info */
index dc36a052766fc2015dd3574a5c0ac3020cd32d5a..fcd9082f3e7f05d93fedc3073e3f6a87c318a6a8 100644 (file)
@@ -878,6 +878,7 @@ static void mct_u232_break_ctl(struct tty_struct *tty, int break_state)
 
        dbg("%sstate=%d", __func__, break_state);
 
+       /* LOCKING */
        if (break_state)
                lcr |= MCT_U232_SET_BREAK;
 
index 07710cf31d0d23ddd83afce4411264c418132afc..82930a7d509327c2797ef474042e0a3d2a4106ac 100644 (file)
@@ -721,10 +721,10 @@ static void mct_u232_break_ctl(struct tty_struct *tty, int break_state)
 
        spin_lock_irqsave(&priv->lock, flags);
        lcr = priv->last_lcr;
-       spin_unlock_irqrestore(&priv->lock, flags);
 
        if (break_state)
                lcr |= MCT_U232_SET_BREAK;
+       spin_unlock_irqrestore(&priv->lock, flags);
 
        mct_u232_set_line_ctrl(serial, lcr);
 } /* mct_u232_break_ctl */
index fda4a6421c44226abf6d905a707eb5e4f5bec505..96a8c7713212871cf98ce1031cdefe8cfdfae430 100644 (file)
@@ -1343,6 +1343,7 @@ static void mos7840_break(struct tty_struct *tty, int break_state)
        else
                data = mos7840_port->shadowLCR & ~LCR_SET_BREAK;
 
+       /* FIXME: no locking on shadowLCR anywhere in driver */
        mos7840_port->shadowLCR = data;
        dbg("mcs7840_break mos7840_port->shadowLCR is %x\n",
            mos7840_port->shadowLCR);
@@ -2214,10 +2215,12 @@ static int mos7840_set_modem_info(struct moschip_port *mos7840_port,
                break;
        }
 
+       lock_kernel();
        mos7840_port->shadowMCR = mcr;
 
        Data = mos7840_port->shadowMCR;
        status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
+       unlock_kernel();
        if (status < 0) {
                dbg("setting MODEM_CONTROL_REGISTER Failed\n");
                return -1;
index 0f2b67244af63718ca2238887d91910109dd92cb..d9bf9a5c20eca522c28341c9828d6493714e8eb6 100644 (file)
@@ -442,7 +442,7 @@ static void sierra_indat_callback(struct urb *urb)
                    " endpoint %02x.", __func__, status, endpoint);
        } else {
                if (urb->actual_length) {
-               tty = tty_port_tty_get(&port->port);
+                       tty = tty_port_tty_get(&port->port);
                        tty_buffer_request_room(tty, urb->actual_length);
                        tty_insert_flip_string(tty, data, urb->actual_length);
                        tty_flip_buffer_push(tty);
index 794b5ffe4397bcfd84f38c3d7affaebac6be77af..080ade223d53fe1306206f8b0f93388f75c17246 100644 (file)
@@ -269,15 +269,19 @@ static void serial_close(struct tty_struct *tty, struct file *filp)
                return;
        }
 
-       --port->port.count;
-       if (port->port.count == 0)
+       if (port->port.count == 1)
                /* only call the device specific close if this
-                * port is being closed by the last owner */
+                * port is being closed by the last owner. Ensure we do
+                * this before we drop the port count. The call is protected
+                * by the port mutex
+                */
                port->serial->type->close(tty, port, filp);
 
-       if (port->port.count == (port->console? 1 : 0)) {
+       if (port->port.count == (port->console ? 2 : 1)) {
                struct tty_struct *tty = tty_port_tty_get(&port->port);
                if (tty) {
+                       /* We must do this before we drop the port count to
+                          zero. */
                        if (tty->driver_data)
                                tty->driver_data = NULL;
                        tty_port_tty_set(&port->port, NULL);
@@ -285,13 +289,14 @@ static void serial_close(struct tty_struct *tty, struct file *filp)
                }
        }
 
-       if (port->port.count == 0) {
+       if (port->port.count == 1) {
                mutex_lock(&port->serial->disc_mutex);
                if (!port->serial->disconnected)
                        usb_autopm_put_interface(port->serial->interface);
                mutex_unlock(&port->serial->disc_mutex);
                module_put(port->serial->type->driver.owner);
        }
+       --port->port.count;
 
        mutex_unlock(&port->mutex);
        usb_serial_put(port->serial);
@@ -334,6 +339,10 @@ static int serial_chars_in_buffer(struct tty_struct *tty)
        dbg("%s = port %d", __func__, port->number);
 
        WARN_ON(!port->port.count);
+       /* if the device was unplugged then any remaining characters
+          fell out of the connector ;) */
+       if (port->serial->disconnected)
+               return 0;
        /* pass on to the driver specific version of this function */
        return port->serial->type->chars_in_buffer(tty);
 }
@@ -373,9 +382,7 @@ static int serial_ioctl(struct tty_struct *tty, struct file *file,
        /* pass on to the driver specific version of this function
           if it is available */
        if (port->serial->type->ioctl) {
-               lock_kernel();
                retval = port->serial->type->ioctl(tty, file, cmd, arg);
-               unlock_kernel();
        } else
                retval = -ENOIOCTLCMD;
        return retval;
@@ -404,11 +411,8 @@ static int serial_break(struct tty_struct *tty, int break_state)
        WARN_ON(!port->port.count);
        /* pass on to the driver specific version of this function
           if it is available */
-       if (port->serial->type->break_ctl) {
-               lock_kernel();
+       if (port->serial->type->break_ctl)
                port->serial->type->break_ctl(tty, break_state);
-               unlock_kernel();
-       }
        return 0;
 }
 
index 5d61b7c06e134d3321d483793ac3973ce804de32..fff96e152c0c16f18c3cecffd4ffae5b0604c2e0 100644 (file)
 #define DEVPTS_SUPER_MAGIC 0x1cd1
 
 #define DEVPTS_DEFAULT_MODE 0600
+/*
+ * ptmx is a new node in /dev/pts and will be unused in legacy (single-
+ * instance) mode. To prevent surprises in user space, set permissions of
+ * ptmx to 0. Use 'chmod' or remount with '-o ptmxmode' to set meaningful
+ * permissions.
+ */
+#define DEVPTS_DEFAULT_PTMX_MODE 0000
 #define PTMX_MINOR     2
 
 extern int pty_limit;                  /* Config limit on Unix98 ptys */
-static DEFINE_IDA(allocated_ptys);
 static DEFINE_MUTEX(allocated_ptys_lock);
 
 static struct vfsmount *devpts_mnt;
-static struct dentry *devpts_root;
 
-static struct {
+struct pts_mount_opts {
        int setuid;
        int setgid;
        uid_t   uid;
        gid_t   gid;
        umode_t mode;
-} config = {.mode = DEVPTS_DEFAULT_MODE};
+       umode_t ptmxmode;
+       int newinstance;
+};
 
 enum {
-       Opt_uid, Opt_gid, Opt_mode,
+       Opt_uid, Opt_gid, Opt_mode, Opt_ptmxmode, Opt_newinstance,
        Opt_err
 };
 
@@ -53,18 +60,50 @@ static const match_table_t tokens = {
        {Opt_uid, "uid=%u"},
        {Opt_gid, "gid=%u"},
        {Opt_mode, "mode=%o"},
+#ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES
+       {Opt_ptmxmode, "ptmxmode=%o"},
+       {Opt_newinstance, "newinstance"},
+#endif
        {Opt_err, NULL}
 };
 
-static int devpts_remount(struct super_block *sb, int *flags, char *data)
+struct pts_fs_info {
+       struct ida allocated_ptys;
+       struct pts_mount_opts mount_opts;
+       struct dentry *ptmx_dentry;
+};
+
+static inline struct pts_fs_info *DEVPTS_SB(struct super_block *sb)
+{
+       return sb->s_fs_info;
+}
+
+static inline struct super_block *pts_sb_from_inode(struct inode *inode)
+{
+#ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES
+       if (inode->i_sb->s_magic == DEVPTS_SUPER_MAGIC)
+               return inode->i_sb;
+#endif
+       return devpts_mnt->mnt_sb;
+}
+
+#define PARSE_MOUNT    0
+#define PARSE_REMOUNT  1
+
+static int parse_mount_options(char *data, int op, struct pts_mount_opts *opts)
 {
        char *p;
 
-       config.setuid  = 0;
-       config.setgid  = 0;
-       config.uid     = 0;
-       config.gid     = 0;
-       config.mode    = DEVPTS_DEFAULT_MODE;
+       opts->setuid  = 0;
+       opts->setgid  = 0;
+       opts->uid     = 0;
+       opts->gid     = 0;
+       opts->mode    = DEVPTS_DEFAULT_MODE;
+       opts->ptmxmode = DEVPTS_DEFAULT_PTMX_MODE;
+
+       /* newinstance makes sense only on initial mount */
+       if (op == PARSE_MOUNT)
+               opts->newinstance = 0;
 
        while ((p = strsep(&data, ",")) != NULL) {
                substring_t args[MAX_OPT_ARGS];
@@ -79,20 +118,32 @@ static int devpts_remount(struct super_block *sb, int *flags, char *data)
                case Opt_uid:
                        if (match_int(&args[0], &option))
                                return -EINVAL;
-                       config.uid = option;
-                       config.setuid = 1;
+                       opts->uid = option;
+                       opts->setuid = 1;
                        break;
                case Opt_gid:
                        if (match_int(&args[0], &option))
                                return -EINVAL;
-                       config.gid = option;
-                       config.setgid = 1;
+                       opts->gid = option;
+                       opts->setgid = 1;
                        break;
                case Opt_mode:
                        if (match_octal(&args[0], &option))
                                return -EINVAL;
-                       config.mode = option & S_IALLUGO;
+                       opts->mode = option & S_IALLUGO;
+                       break;
+#ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES
+               case Opt_ptmxmode:
+                       if (match_octal(&args[0], &option))
+                               return -EINVAL;
+                       opts->ptmxmode = option & S_IALLUGO;
+                       break;
+               case Opt_newinstance:
+                       /* newinstance makes sense only on initial mount */
+                       if (op == PARSE_MOUNT)
+                               opts->newinstance = 1;
                        break;
+#endif
                default:
                        printk(KERN_ERR "devpts: called with bogus options\n");
                        return -EINVAL;
@@ -102,13 +153,108 @@ static int devpts_remount(struct super_block *sb, int *flags, char *data)
        return 0;
 }
 
+#ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES
+static int mknod_ptmx(struct super_block *sb)
+{
+       int mode;
+       int rc = -ENOMEM;
+       struct dentry *dentry;
+       struct inode *inode;
+       struct dentry *root = sb->s_root;
+       struct pts_fs_info *fsi = DEVPTS_SB(sb);
+       struct pts_mount_opts *opts = &fsi->mount_opts;
+
+       mutex_lock(&root->d_inode->i_mutex);
+
+       /* If we have already created ptmx node, return */
+       if (fsi->ptmx_dentry) {
+               rc = 0;
+               goto out;
+       }
+
+       dentry = d_alloc_name(root, "ptmx");
+       if (!dentry) {
+               printk(KERN_NOTICE "Unable to alloc dentry for ptmx node\n");
+               goto out;
+       }
+
+       /*
+        * Create a new 'ptmx' node in this mount of devpts.
+        */
+       inode = new_inode(sb);
+       if (!inode) {
+               printk(KERN_ERR "Unable to alloc inode for ptmx node\n");
+               dput(dentry);
+               goto out;
+       }
+
+       inode->i_ino = 2;
+       inode->i_uid = inode->i_gid = 0;
+       inode->i_blocks = 0;
+       inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+
+       mode = S_IFCHR|opts->ptmxmode;
+       init_special_inode(inode, mode, MKDEV(TTYAUX_MAJOR, 2));
+
+       d_add(dentry, inode);
+
+       fsi->ptmx_dentry = dentry;
+       rc = 0;
+
+       printk(KERN_DEBUG "Created ptmx node in devpts ino %lu\n",
+                       inode->i_ino);
+out:
+       mutex_unlock(&root->d_inode->i_mutex);
+       return rc;
+}
+
+static void update_ptmx_mode(struct pts_fs_info *fsi)
+{
+       struct inode *inode;
+       if (fsi->ptmx_dentry) {
+               inode = fsi->ptmx_dentry->d_inode;
+               inode->i_mode = S_IFCHR|fsi->mount_opts.ptmxmode;
+       }
+}
+#else
+static inline void update_ptmx_mode(struct pts_fs_info *fsi)
+{
+       return;
+}
+#endif
+
+static int devpts_remount(struct super_block *sb, int *flags, char *data)
+{
+       int err;
+       struct pts_fs_info *fsi = DEVPTS_SB(sb);
+       struct pts_mount_opts *opts = &fsi->mount_opts;
+
+       err = parse_mount_options(data, PARSE_REMOUNT, opts);
+
+       /*
+        * parse_mount_options() restores options to default values
+        * before parsing and may have changed ptmxmode. So, update the
+        * mode in the inode too. Bogus options don't fail the remount,
+        * so do this even on error return.
+        */
+       update_ptmx_mode(fsi);
+
+       return err;
+}
+
 static int devpts_show_options(struct seq_file *seq, struct vfsmount *vfs)
 {
-       if (config.setuid)
-               seq_printf(seq, ",uid=%u", config.uid);
-       if (config.setgid)
-               seq_printf(seq, ",gid=%u", config.gid);
-       seq_printf(seq, ",mode=%03o", config.mode);
+       struct pts_fs_info *fsi = DEVPTS_SB(vfs->mnt_sb);
+       struct pts_mount_opts *opts = &fsi->mount_opts;
+
+       if (opts->setuid)
+               seq_printf(seq, ",uid=%u", opts->uid);
+       if (opts->setgid)
+               seq_printf(seq, ",gid=%u", opts->gid);
+       seq_printf(seq, ",mode=%03o", opts->mode);
+#ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES
+       seq_printf(seq, ",ptmxmode=%03o", opts->ptmxmode);
+#endif
 
        return 0;
 }
@@ -119,10 +265,25 @@ static const struct super_operations devpts_sops = {
        .show_options   = devpts_show_options,
 };
 
+static void *new_pts_fs_info(void)
+{
+       struct pts_fs_info *fsi;
+
+       fsi = kzalloc(sizeof(struct pts_fs_info), GFP_KERNEL);
+       if (!fsi)
+               return NULL;
+
+       ida_init(&fsi->allocated_ptys);
+       fsi->mount_opts.mode = DEVPTS_DEFAULT_MODE;
+       fsi->mount_opts.ptmxmode = DEVPTS_DEFAULT_PTMX_MODE;
+
+       return fsi;
+}
+
 static int
 devpts_fill_super(struct super_block *s, void *data, int silent)
 {
-       struct inode * inode;
+       struct inode *inode;
 
        s->s_blocksize = 1024;
        s->s_blocksize_bits = 10;
@@ -130,9 +291,13 @@ devpts_fill_super(struct super_block *s, void *data, int silent)
        s->s_op = &devpts_sops;
        s->s_time_gran = 1;
 
+       s->s_fs_info = new_pts_fs_info();
+       if (!s->s_fs_info)
+               goto fail;
+
        inode = new_inode(s);
        if (!inode)
-               goto fail;
+               goto free_fsi;
        inode->i_ino = 1;
        inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
        inode->i_blocks = 0;
@@ -142,27 +307,226 @@ devpts_fill_super(struct super_block *s, void *data, int silent)
        inode->i_fop = &simple_dir_operations;
        inode->i_nlink = 2;
 
-       devpts_root = s->s_root = d_alloc_root(inode);
+       s->s_root = d_alloc_root(inode);
        if (s->s_root)
                return 0;
-       
-       printk("devpts: get root dentry failed\n");
+
+       printk(KERN_ERR "devpts: get root dentry failed\n");
        iput(inode);
+
+free_fsi:
+       kfree(s->s_fs_info);
 fail:
        return -ENOMEM;
 }
 
+#ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES
+static int compare_init_pts_sb(struct super_block *s, void *p)
+{
+       if (devpts_mnt)
+               return devpts_mnt->mnt_sb == s;
+       return 0;
+}
+
+/*
+ * Safely parse the mount options in @data and update @opts.
+ *
+ * devpts ends up parsing options two times during mount, due to the
+ * two modes of operation it supports. The first parse occurs in
+ * devpts_get_sb() when determining the mode (single-instance or
+ * multi-instance mode). The second parse happens in devpts_remount()
+ * or new_pts_mount() depending on the mode.
+ *
+ * Parsing of options modifies the @data making subsequent parsing
+ * incorrect. So make a local copy of @data and parse it.
+ *
+ * Return: 0 On success, -errno on error
+ */
+static int safe_parse_mount_options(void *data, struct pts_mount_opts *opts)
+{
+       int rc;
+       void *datacp;
+
+       if (!data)
+               return 0;
+
+       /* Use kstrdup() ?  */
+       datacp = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!datacp)
+               return -ENOMEM;
+
+       memcpy(datacp, data, PAGE_SIZE);
+       rc = parse_mount_options((char *)datacp, PARSE_MOUNT, opts);
+       kfree(datacp);
+
+       return rc;
+}
+
+/*
+ * Mount a new (private) instance of devpts.  PTYs created in this
+ * instance are independent of the PTYs in other devpts instances.
+ */
+static int new_pts_mount(struct file_system_type *fs_type, int flags,
+               void *data, struct vfsmount *mnt)
+{
+       int err;
+       struct pts_fs_info *fsi;
+       struct pts_mount_opts *opts;
+
+       printk(KERN_NOTICE "devpts: newinstance mount\n");
+
+       err = get_sb_nodev(fs_type, flags, data, devpts_fill_super, mnt);
+       if (err)
+               return err;
+
+       fsi = DEVPTS_SB(mnt->mnt_sb);
+       opts = &fsi->mount_opts;
+
+       err = parse_mount_options(data, PARSE_MOUNT, opts);
+       if (err)
+               goto fail;
+
+       err = mknod_ptmx(mnt->mnt_sb);
+       if (err)
+               goto fail;
+
+       return 0;
+
+fail:
+       dput(mnt->mnt_sb->s_root);
+       deactivate_super(mnt->mnt_sb);
+       return err;
+}
+
+/*
+ * Check if 'newinstance' mount option was specified in @data.
+ *
+ * Return: -errno      on error (eg: invalid mount options specified)
+ *      : 1            if 'newinstance' mount option was specified
+ *      : 0            if 'newinstance' mount option was NOT specified
+ */
+static int is_new_instance_mount(void *data)
+{
+       int rc;
+       struct pts_mount_opts opts;
+
+       if (!data)
+               return 0;
+
+       rc = safe_parse_mount_options(data, &opts);
+       if (!rc)
+               rc = opts.newinstance;
+
+       return rc;
+}
+
+/*
+ * get_init_pts_sb()
+ *
+ *     This interface is needed to support multiple namespace semantics in
+ *     devpts while preserving backward compatibility of the current 'single-
+ *     namespace' semantics. i.e all mounts of devpts without the 'newinstance'
+ *     mount option should bind to the initial kernel mount, like
+ *     get_sb_single().
+ *
+ *     Mounts with 'newinstance' option create a new private namespace.
+ *
+ *     But for single-mount semantics, devpts cannot use get_sb_single(),
+ *     because get_sb_single()/sget() find and use the super-block from
+ *     the most recent mount of devpts. But that recent mount may be a
+ *     'newinstance' mount and get_sb_single() would pick the newinstance
+ *     super-block instead of the initial super-block.
+ *
+ *     This interface is identical to get_sb_single() except that it
+ *     consistently selects the 'single-namespace' superblock even in the
+ *     presence of the private namespace (i.e 'newinstance') super-blocks.
+ */
+static int get_init_pts_sb(struct file_system_type *fs_type, int flags,
+               void *data, struct vfsmount *mnt)
+{
+       struct super_block *s;
+       int error;
+
+       s = sget(fs_type, compare_init_pts_sb, set_anon_super, NULL);
+       if (IS_ERR(s))
+               return PTR_ERR(s);
+
+       if (!s->s_root) {
+               s->s_flags = flags;
+               error = devpts_fill_super(s, data, flags & MS_SILENT ? 1 : 0);
+               if (error) {
+                       up_write(&s->s_umount);
+                       deactivate_super(s);
+                       return error;
+               }
+               s->s_flags |= MS_ACTIVE;
+       }
+       do_remount_sb(s, flags, data, 0);
+       return simple_set_mnt(mnt, s);
+}
+
+/*
+ * Mount or remount the initial kernel mount of devpts. This type of
+ * mount maintains the legacy, single-instance semantics, while the
+ * kernel still allows multiple-instances.
+ */
+static int init_pts_mount(struct file_system_type *fs_type, int flags,
+               void *data, struct vfsmount *mnt)
+{
+       int err;
+
+       err = get_init_pts_sb(fs_type, flags, data, mnt);
+       if (err)
+               return err;
+
+       err = mknod_ptmx(mnt->mnt_sb);
+       if (err) {
+               dput(mnt->mnt_sb->s_root);
+               deactivate_super(mnt->mnt_sb);
+       }
+
+       return err;
+}
+
 static int devpts_get_sb(struct file_system_type *fs_type,
        int flags, const char *dev_name, void *data, struct vfsmount *mnt)
+{
+       int new;
+
+       new = is_new_instance_mount(data);
+       if (new < 0)
+               return new;
+
+       if (new)
+               return new_pts_mount(fs_type, flags, data, mnt);
+
+       return init_pts_mount(fs_type, flags, data, mnt);
+}
+#else
+/*
+ * This supports only the legacy single-instance semantics (no
+ * multiple-instance semantics)
+ */
+static int devpts_get_sb(struct file_system_type *fs_type, int flags,
+               const char *dev_name, void *data, struct vfsmount *mnt)
 {
        return get_sb_single(fs_type, flags, data, devpts_fill_super, mnt);
 }
+#endif
+
+static void devpts_kill_sb(struct super_block *sb)
+{
+       struct pts_fs_info *fsi = DEVPTS_SB(sb);
+
+       kfree(fsi);
+       kill_litter_super(sb);
+}
 
 static struct file_system_type devpts_fs_type = {
        .owner          = THIS_MODULE,
        .name           = "devpts",
        .get_sb         = devpts_get_sb,
-       .kill_sb        = kill_anon_super,
+       .kill_sb        = devpts_kill_sb,
 };
 
 /*
@@ -172,16 +536,17 @@ static struct file_system_type devpts_fs_type = {
 
 int devpts_new_index(struct inode *ptmx_inode)
 {
+       struct super_block *sb = pts_sb_from_inode(ptmx_inode);
+       struct pts_fs_info *fsi = DEVPTS_SB(sb);
        int index;
        int ida_ret;
 
 retry:
-       if (!ida_pre_get(&allocated_ptys, GFP_KERNEL)) {
+       if (!ida_pre_get(&fsi->allocated_ptys, GFP_KERNEL))
                return -ENOMEM;
-       }
 
        mutex_lock(&allocated_ptys_lock);
-       ida_ret = ida_get_new(&allocated_ptys, &index);
+       ida_ret = ida_get_new(&fsi->allocated_ptys, &index);
        if (ida_ret < 0) {
                mutex_unlock(&allocated_ptys_lock);
                if (ida_ret == -EAGAIN)
@@ -190,7 +555,7 @@ retry:
        }
 
        if (index >= pty_limit) {
-               ida_remove(&allocated_ptys, index);
+               ida_remove(&fsi->allocated_ptys, index);
                mutex_unlock(&allocated_ptys_lock);
                return -EIO;
        }
@@ -200,18 +565,26 @@ retry:
 
 void devpts_kill_index(struct inode *ptmx_inode, int idx)
 {
+       struct super_block *sb = pts_sb_from_inode(ptmx_inode);
+       struct pts_fs_info *fsi = DEVPTS_SB(sb);
+
        mutex_lock(&allocated_ptys_lock);
-       ida_remove(&allocated_ptys, idx);
+       ida_remove(&fsi->allocated_ptys, idx);
        mutex_unlock(&allocated_ptys_lock);
 }
 
 int devpts_pty_new(struct inode *ptmx_inode, struct tty_struct *tty)
 {
-       int number = tty->index; /* tty layer puts index from devpts_new_index() in here */
+       /* tty layer puts index from devpts_new_index() in here */
+       int number = tty->index;
        struct tty_driver *driver = tty->driver;
        dev_t device = MKDEV(driver->major, driver->minor_start+number);
        struct dentry *dentry;
-       struct inode *inode = new_inode(devpts_mnt->mnt_sb);
+       struct super_block *sb = pts_sb_from_inode(ptmx_inode);
+       struct inode *inode = new_inode(sb);
+       struct dentry *root = sb->s_root;
+       struct pts_fs_info *fsi = DEVPTS_SB(sb);
+       struct pts_mount_opts *opts = &fsi->mount_opts;
        char s[12];
 
        /* We're supposed to be given the slave end of a pty */
@@ -221,25 +594,25 @@ int devpts_pty_new(struct inode *ptmx_inode, struct tty_struct *tty)
        if (!inode)
                return -ENOMEM;
 
-       inode->i_ino = number+2;
-       inode->i_uid = config.setuid ? config.uid : current_fsuid();
-       inode->i_gid = config.setgid ? config.gid : current_fsgid();
+       inode->i_ino = number + 3;
+       inode->i_uid = opts->setuid ? opts->uid : current_fsuid();
+       inode->i_gid = opts->setgid ? opts->gid : current_fsgid();
        inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
-       init_special_inode(inode, S_IFCHR|config.mode, device);
+       init_special_inode(inode, S_IFCHR|opts->mode, device);
        inode->i_private = tty;
        tty->driver_data = inode;
 
        sprintf(s, "%d", number);
 
-       mutex_lock(&devpts_root->d_inode->i_mutex);
+       mutex_lock(&root->d_inode->i_mutex);
 
-       dentry = d_alloc_name(devpts_root, s);
+       dentry = d_alloc_name(root, s);
        if (!IS_ERR(dentry)) {
                d_add(dentry, inode);
-               fsnotify_create(devpts_root->d_inode, dentry);
+               fsnotify_create(root->d_inode, dentry);
        }
 
-       mutex_unlock(&devpts_root->d_inode->i_mutex);
+       mutex_unlock(&root->d_inode->i_mutex);
 
        return 0;
 }
@@ -256,20 +629,27 @@ struct tty_struct *devpts_get_tty(struct inode *pts_inode, int number)
 void devpts_pty_kill(struct tty_struct *tty)
 {
        struct inode *inode = tty->driver_data;
+       struct super_block *sb = pts_sb_from_inode(inode);
+       struct dentry *root = sb->s_root;
        struct dentry *dentry;
 
        BUG_ON(inode->i_rdev == MKDEV(TTYAUX_MAJOR, PTMX_MINOR));
 
-       mutex_lock(&devpts_root->d_inode->i_mutex);
+       mutex_lock(&root->d_inode->i_mutex);
 
        dentry = d_find_alias(inode);
-       if (dentry && !IS_ERR(dentry)) {
+       if (IS_ERR(dentry))
+               goto out;
+
+       if (dentry) {
                inode->i_nlink--;
                d_delete(dentry);
-               dput(dentry);
+               dput(dentry);   /* d_alloc_name() in devpts_pty_new() */
        }
 
-       mutex_unlock(&devpts_root->d_inode->i_mutex);
+       dput(dentry);           /* d_find_alias above */
+out:
+       mutex_unlock(&root->d_inode->i_mutex);
 }
 
 static int __init init_devpts_fs(void)
index 3209dd46ea7d98ce0f846d07aad0222e39764606..b24ff086a662af04535fc3707a838ce4c526753f 100644 (file)
@@ -31,7 +31,7 @@ struct pciserial_board {
 struct serial_private;
 
 struct serial_private *
-pciserial_init_ports(struct pci_dev *dev, struct pciserial_board *board);
+pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board);
 void pciserial_remove_ports(struct serial_private *priv);
 void pciserial_suspend_ports(struct serial_private *priv);
 void pciserial_resume_ports(struct serial_private *priv);
index 4cc9139398171f8324698a205245e213e4a9b37c..fadff28505bb9686d4278add4b1cc17350def785 100644 (file)
@@ -21,7 +21,6 @@ struct real_driver {
   void                    (*enable_tx_interrupts) (void *);
   void                    (*disable_rx_interrupts) (void *);
   void                    (*enable_rx_interrupts) (void *);
-  int                     (*get_CD) (void *);
   void                    (*shutdown_port) (void*);
   int                     (*set_real_termios) (void*);
   int                     (*chars_in_buffer) (void*);
index 0d1840723249c046d09ba89d0f9f56b67e035774..7faca98c7d1448885a0ecf31f2453fc908ec35e7 100644 (file)
@@ -59,9 +59,7 @@ struct stliport {
        unsigned int            devnr;
        int                     baud_base;
        int                     custom_divisor;
-       int                     close_delay;
        int                     closing_wait;
-       int                     openwaitcnt;
        int                     rc;
        int                     argsize;
        void                    *argp;
index b6e6944542807e75d43d17b4d2e432c8f875b090..218c73b1e6d49636d8ec6041a699ad50c5a0c8bd 100644 (file)
 #define PCI_DEVICE_ID_SIIG_8S_20x_650  0x2081
 #define PCI_DEVICE_ID_SIIG_8S_20x_850  0x2082
 #define PCI_SUBDEVICE_ID_SIIG_QUARTET_SERIAL   0x2050
+#define PCI_SUBDEVICE_ID_SIIG_DUAL_SERIAL      0x2530
 
 #define PCI_VENDOR_ID_RADISYS          0x1331
 
 #define PCI_DEVICE_ID_SEALEVEL_UCOMM232        0x7202
 #define PCI_DEVICE_ID_SEALEVEL_COMM4   0x7401
 #define PCI_DEVICE_ID_SEALEVEL_COMM8   0x7801
+#define PCI_DEVICE_ID_SEALEVEL_7803    0x7803
 #define PCI_DEVICE_ID_SEALEVEL_UCOMM8  0x7804
 
 #define PCI_VENDOR_ID_HYPERCOPE                0x1365
index 1ea8d9265bf67c5bc52d1a43b2557d9ae661c2df..9136cc5608c3df2b15145ab7f1fbe09c966fd8f9 100644 (file)
@@ -10,8 +10,9 @@
 #ifndef _LINUX_SERIAL_H
 #define _LINUX_SERIAL_H
 
-#ifdef __KERNEL__
 #include <linux/types.h>
+
+#ifdef __KERNEL__
 #include <asm/page.h>
 
 /*
index 3d37c94abbc80622732e4a0793ccda55ea6227a7..d4d2a78ad43e607bb9b3d2f3b84970c64a36fb1a 100644 (file)
@@ -28,6 +28,9 @@ struct plat_serial8250_port {
        unsigned char   iotype;         /* UPIO_* */
        unsigned char   hub6;
        upf_t           flags;          /* UPF_* flags */
+       unsigned int    type;           /* If UPF_FIXED_TYPE */
+       unsigned int    (*serial_in)(struct uart_port *, int);
+       void            (*serial_out)(struct uart_port *, int, int);
 };
 
 /*
index feb3b939ec4bc779cb4dd2907e5fc1292af7af1a..b4199841f1fc92e973e1b03f2a9472b8faaac32a 100644 (file)
@@ -40,7 +40,8 @@
 #define PORT_NS16550A  14
 #define PORT_XSCALE    15
 #define PORT_RM9000    16      /* PMC-Sierra RM9xxx internal UART */
-#define PORT_MAX_8250  16      /* max port ID */
+#define PORT_OCTEON    17      /* Cavium OCTEON internal UART */
+#define PORT_MAX_8250  17      /* max port ID */
 
 /*
  * ARM specific type numbers.  These are not currently guaranteed
@@ -248,6 +249,8 @@ struct uart_port {
        spinlock_t              lock;                   /* port lock */
        unsigned long           iobase;                 /* in/out[bwl] */
        unsigned char __iomem   *membase;               /* read/write[bwl] */
+       unsigned int            (*serial_in)(struct uart_port *, int);
+       void                    (*serial_out)(struct uart_port *, int, int);
        unsigned int            irq;                    /* irq number */
        unsigned int            uartclk;                /* base uart clock */
        unsigned int            fifosize;               /* tx fifo size */
@@ -293,6 +296,8 @@ struct uart_port {
 #define UPF_MAGIC_MULTIPLIER   ((__force upf_t) (1 << 16))
 #define UPF_CONS_FLOW          ((__force upf_t) (1 << 23))
 #define UPF_SHARE_IRQ          ((__force upf_t) (1 << 24))
+/* The exact UART type is known and should not be probed.  */
+#define UPF_FIXED_TYPE         ((__force upf_t) (1 << 27))
 #define UPF_BOOT_AUTOCONF      ((__force upf_t) (1 << 28))
 #define UPF_FIXED_PORT         ((__force upf_t) (1 << 29))
 #define UPF_DEAD               ((__force upf_t) (1 << 30))
@@ -315,36 +320,14 @@ struct uart_port {
        void                    *private_data;          /* generic platform data pointer */
 };
 
-/*
- * This is the state information which is persistent across opens.
- * The low level driver must not to touch any elements contained
- * within.
- */
-struct uart_state {
-       unsigned int            close_delay;            /* msec */
-       unsigned int            closing_wait;           /* msec */
-
-#define USF_CLOSING_WAIT_INF   (0)
-#define USF_CLOSING_WAIT_NONE  (~0U)
-
-       int                     count;
-       int                     pm_state;
-       struct uart_info        *info;
-       struct uart_port        *port;
-
-       struct mutex            mutex;
-};
-
-#define UART_XMIT_SIZE PAGE_SIZE
-
-typedef unsigned int __bitwise__ uif_t;
-
 /*
  * This is the state information which is only valid when the port
- * is open; it may be freed by the core driver once the device has
+ * is open; it may be cleared the core driver once the device has
  * been closed.  Either the low level driver or the core can modify
  * stuff here.
  */
+typedef unsigned int __bitwise__ uif_t;
+
 struct uart_info {
        struct tty_port         port;
        struct circ_buf         xmit;
@@ -366,6 +349,29 @@ struct uart_info {
        wait_queue_head_t       delta_msr_wait;
 };
 
+/*
+ * This is the state information which is persistent across opens.
+ * The low level driver must not to touch any elements contained
+ * within.
+ */
+struct uart_state {
+       unsigned int            close_delay;            /* msec */
+       unsigned int            closing_wait;           /* msec */
+
+#define USF_CLOSING_WAIT_INF   (0)
+#define USF_CLOSING_WAIT_NONE  (~0U)
+
+       int                     count;
+       int                     pm_state;
+       struct uart_info        info;
+       struct uart_port        *port;
+
+       struct mutex            mutex;
+};
+
+#define UART_XMIT_SIZE PAGE_SIZE
+
+
 /* number of characters left in xmit buffer before we ask for more */
 #define WAKEUP_CHARS           256
 
@@ -439,8 +445,13 @@ int uart_resume_port(struct uart_driver *reg, struct uart_port *port);
 #define uart_circ_chars_free(circ)     \
        (CIRC_SPACE((circ)->head, (circ)->tail, UART_XMIT_SIZE))
 
-#define uart_tx_stopped(portp)         \
-       ((portp)->info->port.tty->stopped || (portp)->info->port.tty->hw_stopped)
+static inline int uart_tx_stopped(struct uart_port *port)
+{
+       struct tty_struct *tty = port->info->port.tty;
+       if(tty->stopped || tty->hw_stopped)
+               return 1;
+       return 0;
+}
 
 /*
  * The following are helper functions for the low level drivers.
@@ -451,7 +462,7 @@ uart_handle_sysrq_char(struct uart_port *port, unsigned int ch)
 #ifdef SUPPORT_SYSRQ
        if (port->sysrq) {
                if (ch && time_before(jiffies, port->sysrq)) {
-                       handle_sysrq(ch, port->info ? port->info->port.tty : NULL);
+                       handle_sysrq(ch, port->info->port.tty);
                        port->sysrq = 0;
                        return 1;
                }
index 3f4954c55e53e3fb5e41c108f0b6797d7446820a..fc39db95499fbab4142800b24faf52b182fae113 100644 (file)
@@ -180,8 +180,17 @@ struct signal_struct;
  * until a hangup so don't use the wrong path.
  */
 
+struct tty_port;
+
+struct tty_port_operations {
+       /* Return 1 if the carrier is raised */
+       int (*carrier_raised)(struct tty_port *port);
+       void (*raise_dtr_rts)(struct tty_port *port);
+};
+       
 struct tty_port {
        struct tty_struct       *tty;           /* Back pointer */
+       const struct tty_port_operations *ops;  /* Port operations */
        spinlock_t              lock;           /* Lock protecting tty field */
        int                     blocked_open;   /* Waiting to open */
        int                     count;          /* Usage count */
@@ -253,6 +262,7 @@ struct tty_struct {
        unsigned int column;
        unsigned char lnext:1, erasing:1, raw:1, real_raw:1, icanon:1;
        unsigned char closing:1;
+       unsigned char echo_overrun:1;
        unsigned short minimum_to_wake;
        unsigned long overrun_time;
        int num_overrun;
@@ -262,11 +272,16 @@ struct tty_struct {
        int read_tail;
        int read_cnt;
        unsigned long read_flags[N_TTY_BUF_SIZE/(8*sizeof(unsigned long))];
+       unsigned char *echo_buf;
+       unsigned int echo_pos;
+       unsigned int echo_cnt;
        int canon_data;
        unsigned long canon_head;
        unsigned int canon_column;
        struct mutex atomic_read_lock;
        struct mutex atomic_write_lock;
+       struct mutex output_lock;
+       struct mutex echo_lock;
        unsigned char *write_buf;
        int write_cnt;
        spinlock_t read_lock;
@@ -295,6 +310,7 @@ struct tty_struct {
 #define TTY_PUSH               6       /* n_tty private */
 #define TTY_CLOSING            7       /* ->close() in progress */
 #define TTY_LDISC              9       /* Line discipline attached */
+#define TTY_LDISC_CHANGING     10      /* Line discipline changing */
 #define TTY_HW_COOK_OUT        14      /* Hardware can do output cooking */
 #define TTY_HW_COOK_IN                 15      /* Hardware can do input cooking */
 #define TTY_PTY_LOCK           16      /* pty private */
@@ -354,8 +370,7 @@ extern int tty_write_room(struct tty_struct *tty);
 extern void tty_driver_flush_buffer(struct tty_struct *tty);
 extern void tty_throttle(struct tty_struct *tty);
 extern void tty_unthrottle(struct tty_struct *tty);
-extern int tty_do_resize(struct tty_struct *tty, struct tty_struct *real_tty,
-                                               struct winsize *ws);
+extern int tty_do_resize(struct tty_struct *tty, struct winsize *ws);
 extern void tty_shutdown(struct tty_struct *tty);
 extern void tty_free_termios(struct tty_struct *tty);
 extern int is_current_pgrp_orphaned(void);
@@ -421,6 +436,14 @@ extern int tty_port_alloc_xmit_buf(struct tty_port *port);
 extern void tty_port_free_xmit_buf(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 int tty_port_carrier_raised(struct tty_port *port);
+extern void tty_port_raise_dtr_rts(struct tty_port *port);
+extern void tty_port_hangup(struct tty_port *port);
+extern int tty_port_block_til_ready(struct tty_port *port,
+                               struct tty_struct *tty, struct file *filp);
+extern int tty_port_close_start(struct tty_port *port,
+                               struct tty_struct *tty, struct file *filp);
+extern void tty_port_close_end(struct tty_port *port, struct tty_struct *tty);
 
 extern int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc);
 extern int tty_unregister_ldisc(int disc);
index 78416b901589cd08cb1ea1410e1ac61986c2f4e0..08e088334dba25288b8fba8423dfcb58774c833a 100644 (file)
  *     Optional: If not provided then the write method is called under
  *     the atomic write lock to keep it serialized with the ldisc.
  *
- * int (*resize)(struct tty_struct *tty, struct tty_struct *real_tty,
- *                             unsigned int rows, unsigned int cols);
+ * int (*resize)(struct tty_struct *tty, struct winsize *ws)
  *
  *     Called when a termios request is issued which changes the
  *     requested terminal geometry.
@@ -258,8 +257,7 @@ struct tty_operations {
        int (*tiocmget)(struct tty_struct *tty, struct file *file);
        int (*tiocmset)(struct tty_struct *tty, struct file *file,
                        unsigned int set, unsigned int clear);
-       int (*resize)(struct tty_struct *tty, struct tty_struct *real_tty,
-                               struct winsize *ws);
+       int (*resize)(struct tty_struct *tty, struct winsize *ws);
        int (*set_termiox)(struct tty_struct *tty, struct termiox *tnew);
 #ifdef CONFIG_CONSOLE_POLL
        int (*poll_init)(struct tty_driver *driver, int line, char *options);
index e4e2caeb9d82d9d1061e27b64c10476125806846..086d5ef098fd0b541359c8bd8448075406ef05cf 100644 (file)
@@ -371,9 +371,8 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
        IRDA_DEBUG(2, "%s()\n", __func__ );
 
        line = tty->index;
-       if ((line < 0) || (line >= IRCOMM_TTY_PORTS)) {
+       if (line >= IRCOMM_TTY_PORTS)
                return -ENODEV;
-       }
 
        /* Check if instance already exists */
        self = hashbin_lock_find(ircomm_tty, line, NULL);
@@ -405,6 +404,8 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
                 * Force TTY into raw mode by default which is usually what
                 * we want for IrCOMM and IrLPT. This way applications will
                 * not have to twiddle with printcap etc.
+                *
+                * Note this is completely usafe and doesn't work properly
                 */
                tty->termios->c_iflag = 0;
                tty->termios->c_oflag = 0;