Merge branch 'kvm-updates/2.6.29' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 2 Jan 2009 19:41:11 +0000 (11:41 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 2 Jan 2009 19:41:11 +0000 (11:41 -0800)
* 'kvm-updates/2.6.29' of git://git.kernel.org/pub/scm/linux/kernel/git/avi/kvm: (140 commits)
  KVM: MMU: handle large host sptes on invlpg/resync
  KVM: Add locking to virtual i8259 interrupt controller
  KVM: MMU: Don't treat a global pte as such if cr4.pge is cleared
  MAINTAINERS: Maintainership changes for kvm/ia64
  KVM: ia64: Fix kvm_arch_vcpu_ioctl_[gs]et_regs()
  KVM: x86: Rework user space NMI injection as KVM_CAP_USER_NMI
  KVM: VMX: Fix pending NMI-vs.-IRQ race for user space irqchip
  KVM: fix handling of ACK from shared guest IRQ
  KVM: MMU: check for present pdptr shadow page in walk_shadow
  KVM: Consolidate userspace memory capability reporting into common code
  KVM: Advertise the bug in memory region destruction as fixed
  KVM: use cpumask_var_t for cpus_hardware_enabled
  KVM: use modern cpumask primitives, no cpumask_t on stack
  KVM: Extract core of kvm_flush_remote_tlbs/kvm_reload_remote_mmus
  KVM: set owner of cpu and vm file operations
  anon_inodes: use fops->owner for module refcount
  x86: KVM guest: kvm_get_tsc_khz: return khz, not lpj
  KVM: MMU: prepopulate the shadow on invlpg
  KVM: MMU: skip global pgtables on sync due to cr3 switch
  KVM: MMU: collapse remote TLB flushes on root sync
  ...

263 files changed:
Documentation/ABI/testing/sysfs-class-uwb_rc
Documentation/feature-removal-schedule.txt
Documentation/filesystems/Locking
Documentation/filesystems/devpts.txt [new file with mode: 0644]
Documentation/filesystems/files.txt
Documentation/filesystems/vfs.txt
Documentation/usb/wusb-cbaf
MAINTAINERS
arch/alpha/kernel/init_task.c
arch/arm/kernel/init_task.c
arch/avr32/kernel/init_task.c
arch/blackfin/kernel/init_task.c
arch/cris/kernel/process.c
arch/frv/kernel/init_task.c
arch/h8300/kernel/init_task.c
arch/ia64/kernel/init_task.c
arch/m32r/kernel/init_task.c
arch/m68k/kernel/process.c
arch/m68knommu/kernel/init_task.c
arch/mips/kernel/init_task.c
arch/mn10300/kernel/init_task.c
arch/parisc/kernel/init_task.c
arch/powerpc/kernel/init_task.c
arch/powerpc/oprofile/cell/spu_task_sync.c
arch/s390/kernel/init_task.c
arch/sh/kernel/init_task.c
arch/sparc/kernel/init_task.c
arch/um/kernel/init_task.c
arch/x86/kernel/init_task.c
arch/x86/kernel/io_apic.c
arch/x86/mm/init_32.c
arch/xtensa/kernel/init_task.c
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/i8k.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/ide/Kconfig
drivers/ide/Makefile
drivers/ide/ide-atapi.c
drivers/ide/ide-cd.c
drivers/ide/ide-cd.h
drivers/ide/ide-floppy.c
drivers/ide/ide-floppy_ioctl.c
drivers/ide/ide-io.c
drivers/ide/ide-ioctls.c
drivers/ide/ide-park.c
drivers/ide/ide-probe.c
drivers/ide/ide-sysfs.c [new file with mode: 0644]
drivers/ide/ide-tape.c
drivers/ide/ide.c
drivers/ide/tx4938ide.c
drivers/ide/tx4939ide.c
drivers/net/usb/hso.c
drivers/oprofile/buffer_sync.c
drivers/scsi/Kconfig
drivers/scsi/Makefile
drivers/scsi/ide-scsi.c [deleted file]
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/host/hwa-hc.c
drivers/usb/host/whci/Kbuild
drivers/usb/host/whci/asl.c
drivers/usb/host/whci/debug.c [new file with mode: 0644]
drivers/usb/host/whci/hcd.c
drivers/usb/host/whci/hw.c
drivers/usb/host/whci/int.c
drivers/usb/host/whci/pzl.c
drivers/usb/host/whci/qset.c
drivers/usb/host/whci/whcd.h
drivers/usb/host/whci/whci-hc.h
drivers/usb/host/whci/wusb.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
drivers/usb/wusbcore/cbaf.c
drivers/usb/wusbcore/crypto.c
drivers/usb/wusbcore/dev-sysfs.c
drivers/usb/wusbcore/devconnect.c
drivers/usb/wusbcore/mmc.c
drivers/usb/wusbcore/pal.c
drivers/usb/wusbcore/reservation.c
drivers/usb/wusbcore/rh.c
drivers/usb/wusbcore/security.c
drivers/usb/wusbcore/wa-nep.c
drivers/usb/wusbcore/wa-rpipe.c
drivers/usb/wusbcore/wa-xfer.c
drivers/usb/wusbcore/wusbhc.h
drivers/uwb/Makefile
drivers/uwb/address.c
drivers/uwb/allocator.c [new file with mode: 0644]
drivers/uwb/beacon.c
drivers/uwb/driver.c
drivers/uwb/drp-avail.c
drivers/uwb/drp-ie.c
drivers/uwb/drp.c
drivers/uwb/est.c
drivers/uwb/hwa-rc.c
drivers/uwb/i1480/dfu/dfu.c
drivers/uwb/i1480/dfu/mac.c
drivers/uwb/i1480/dfu/usb.c
drivers/uwb/i1480/i1480u-wlp/lc.c
drivers/uwb/i1480/i1480u-wlp/netdev.c
drivers/uwb/i1480/i1480u-wlp/rx.c
drivers/uwb/i1480/i1480u-wlp/sysfs.c
drivers/uwb/i1480/i1480u-wlp/tx.c
drivers/uwb/ie-rcv.c [new file with mode: 0644]
drivers/uwb/ie.c
drivers/uwb/lc-dev.c
drivers/uwb/lc-rc.c
drivers/uwb/neh.c
drivers/uwb/pal.c
drivers/uwb/radio.c [new file with mode: 0644]
drivers/uwb/reset.c
drivers/uwb/rsv.c
drivers/uwb/umc-bus.c
drivers/uwb/umc-dev.c
drivers/uwb/uwb-debug.c
drivers/uwb/uwb-internal.h
drivers/uwb/uwbd.c
drivers/uwb/whc-rc.c
drivers/uwb/whci.c
drivers/uwb/wlp/eda.c
drivers/uwb/wlp/messages.c
drivers/uwb/wlp/sysfs.c
drivers/uwb/wlp/txrx.c
drivers/uwb/wlp/wlp-internal.h
drivers/uwb/wlp/wlp-lc.c
drivers/uwb/wlp/wss-lc.c
drivers/xen/events.c
fs/Kconfig
fs/Makefile
fs/bad_inode.c
fs/befs/linuxvfs.c
fs/block_dev.c
fs/cifs/Makefile
fs/cifs/cifsfs.c
fs/cifs/cifsfs.h
fs/cifs/fcntl.c [deleted file]
fs/dcache.c
fs/dcookies.c
fs/devpts/inode.c
fs/ecryptfs/inode.c
fs/exec.c
fs/ext2/ialloc.c
fs/ext2/inode.c
fs/ext2/namei.c
fs/ext3/ialloc.c
fs/ext3/inode.c
fs/ext3/namei.c
fs/ext4/ialloc.c
fs/ext4/inode.c
fs/ext4/namei.c
fs/fat/dir.c
fs/fat/inode.c
fs/fat/namei_vfat.c
fs/file_table.c
fs/freevxfs/vxfs_inode.c
fs/inode.c
fs/jfs/jfs_inode.c
fs/jfs/namei.c
fs/namei.c
fs/namespace.c
fs/nfsctl.c
fs/notify/Kconfig [new file with mode: 0644]
fs/notify/Makefile [new file with mode: 0644]
fs/notify/dnotify/Kconfig [new file with mode: 0644]
fs/notify/dnotify/Makefile [new file with mode: 0644]
fs/notify/dnotify/dnotify.c [moved from fs/dnotify.c with 98% similarity]
fs/notify/inotify/Kconfig [new file with mode: 0644]
fs/notify/inotify/Makefile [new file with mode: 0644]
fs/notify/inotify/inotify.c [moved from fs/inotify.c with 100% similarity]
fs/notify/inotify/inotify_user.c [moved from fs/inotify_user.c with 100% similarity]
fs/open.c
fs/proc/stat.c
fs/reiserfs/inode.c
fs/reiserfs/namei.c
fs/seq_file.c
fs/sysv/inode.c
include/linux/8250_pci.h
include/linux/compiler-gcc.h
include/linux/compiler-gcc3.h
include/linux/compiler-gcc4.h
include/linux/compiler.h
include/linux/dcache.h
include/linux/fdtable.h
include/linux/fs.h
include/linux/fs_struct.h
include/linux/generic_serial.h
include/linux/ide.h
include/linux/init_task.h
include/linux/interrupt.h
include/linux/irq.h
include/linux/irqnr.h
include/linux/istallion.h
include/linux/namei.h
include/linux/pci_ids.h
include/linux/security.h
include/linux/serial.h
include/linux/serial_8250.h
include/linux/serial_core.h
include/linux/tty.h
include/linux/tty_driver.h
include/linux/usb/wusb-wa.h
include/linux/uwb.h
include/linux/uwb/debug-cmd.h
include/linux/uwb/debug.h [deleted file]
include/linux/uwb/spec.h
include/linux/uwb/umc.h
include/linux/wlp.h
init/main.c
kernel/hrtimer.c
kernel/irq/autoprobe.c
kernel/irq/handle.c
kernel/irq/numa_migrate.c
kernel/irq/spurious.c
kernel/softirq.c
net/irda/ircomm/ircomm_tty.c
net/unix/af_unix.c
security/Kconfig
security/capability.c
security/security.c

index a0d18dbeb7a9ea8d02565ebd0c2040c72e224668..6a5fd072849d7d7b402bd0a141a21dc5ece97fe3 100644 (file)
@@ -32,14 +32,16 @@ Contact:        linux-usb@vger.kernel.org
 Description:
                 Write:
 
-                <channel> [<bpst offset>]
+                <channel>
 
-                to start beaconing on a specific channel, or stop
-                beaconing if <channel> is -1.  Valid channels depends
-                on the radio controller's supported band groups.
+                to force a specific channel to be used when beaconing,
+                or, if <channel> is -1, to prohibit beaconing.  If
+                <channel> is 0, then the default channel selection
+                algorithm will be used.  Valid channels depends on the
+                radio controller's supported band groups.
 
-                <bpst offset> may be used to try and join a specific
-                beacon group if more than one was found during a scan.
+                Reading returns the currently active channel, or -1 if
+                the radio controller is not beaconing.
 
 What:           /sys/class/uwb_rc/uwbN/scan
 Date:           July 2008
index dc7c681e532cacf9fbf9ec0f692e9fb2bd5740e7..df18d87c483796907378586f9b3d11955323b140 100644 (file)
@@ -310,15 +310,6 @@ Who:  Krzysztof Piotr Oledzki <ole@ans.pl>
 
 ---------------------------
 
-What: ide-scsi (BLK_DEV_IDESCSI)
-When: 2.6.29
-Why:  The 2.6 kernel supports direct writing to ide CD drives, which
-      eliminates the need for ide-scsi. The new method is more
-      efficient in every way.
-Who:  FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
-
----------------------------
-
 What:  i2c_attach_client(), i2c_detach_client(), i2c_driver->detach_client()
 When:  2.6.29 (ideally) or 2.6.30 (more likely)
 Why:   Deprecated by the new (standard) device driver binding model. Use
index 23d2f4460debf2122676e83a6d4c9139df889253..ccec55394380393ccf69a0272078ebd5465ceae3 100644 (file)
@@ -394,7 +394,6 @@ prototypes:
        unsigned long (*get_unmapped_area)(struct file *, unsigned long,
                        unsigned long, unsigned long, unsigned long);
        int (*check_flags)(int);
-       int (*dir_notify)(struct file *, unsigned long);
 };
 
 locking rules:
@@ -424,7 +423,6 @@ sendfile:           no
 sendpage:              no
 get_unmapped_area:     no
 check_flags:           no
-dir_notify:            no
 
 ->llseek() locking has moved from llseek to the individual llseek
 implementations.  If your fs is not using generic_file_llseek, you
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 bb0142f6108458f6ccd27b90e965a6bdf820e501..ac2facc50d2a2b2914d10a3268c3ae375ae57d6c 100644 (file)
@@ -76,13 +76,13 @@ the fdtable structure -
 5. Handling of the file structures is special. Since the look-up
    of the fd (fget()/fget_light()) are lock-free, it is possible
    that look-up may race with the last put() operation on the
-   file structure. This is avoided using atomic_inc_not_zero()
+   file structure. This is avoided using atomic_long_inc_not_zero()
    on ->f_count :
 
        rcu_read_lock();
        file = fcheck_files(files, fd);
        if (file) {
-               if (atomic_inc_not_zero(&file->f_count))
+               if (atomic_long_inc_not_zero(&file->f_count))
                        *fput_needed = 1;
                else
                /* Didn't get the reference, someone's freed */
@@ -92,7 +92,7 @@ the fdtable structure -
        ....
        return file;
 
-   atomic_inc_not_zero() detects if refcounts is already zero or
+   atomic_long_inc_not_zero() detects if refcounts is already zero or
    goes to zero during increment. If it does, we fail
    fget()/fget_light().
 
index 5579bda58a6dadc3b793b208e032e1cc6456ad33..ef19afa186a9dd81a973d624940a30c4e5d4bb83 100644 (file)
@@ -733,7 +733,6 @@ struct file_operations {
        ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
        unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
        int (*check_flags)(int);
-       int (*dir_notify)(struct file *filp, unsigned long arg);
        int (*flock) (struct file *, int, struct file_lock *);
        ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, size_t, unsigned int);
        ssize_t (*splice_read)(struct file *, struct pipe_inode_info *, size_t, unsigned int);
@@ -800,8 +799,6 @@ otherwise noted.
 
   check_flags: called by the fcntl(2) system call for F_SETFL command
 
-  dir_notify: called by the fcntl(2) system call for F_NOTIFY command
-
   flock: called by the flock(2) system call
 
   splice_write: called by the VFS to splice data from a pipe to a file. This
@@ -931,7 +928,7 @@ manipulate dentries:
   d_lookup: look up a dentry given its parent and path name component
        It looks up the child of that given name from the dcache
        hash table. If it is found, the reference count is incremented
-       and the dentry is returned. The caller must use d_put()
+       and the dentry is returned. The caller must use dput()
        to free the dentry when it finishes using it.
 
 For further information on dentry locking, please refer to the document
index 2e78b70f3adccf8bc5f16c13990d042ec8c2b03f..426ddaaef96f423812579908992cc464b15044bf 100644 (file)
@@ -80,12 +80,6 @@ case $1 in
     start)
         for dev in ${2:-$hdevs}
           do
-          uwb_rc=$(readlink -f $dev/uwb_rc)
-          if cat $uwb_rc/beacon | grep -q -- "-1"
-              then
-              echo 13 0 > $uwb_rc/beacon
-              echo I: started beaconing on ch 13 on $(basename $uwb_rc) >&2
-          fi
           echo $host_CHID > $dev/wusb_chid
           echo I: started host $(basename $dev) >&2
         done
@@ -95,9 +89,6 @@ case $1 in
           do
           echo 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 > $dev/wusb_chid
           echo I: stopped host $(basename $dev) >&2
-          uwb_rc=$(readlink -f $dev/uwb_rc)
-          echo -1 | cat > $uwb_rc/beacon
-          echo I: stopped beaconing on $(basename $uwb_rc) >&2
         done
         ;;
     set-chid)
index 4209b7148758ecada87eb5a45166c006d63b6e3f..befacf07729f7c88a46d2776ab3d662968f344b8 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
@@ -2146,11 +2152,6 @@ M:       Gadi Oxman <gadio@netvision.net.il>
 L:     linux-kernel@vger.kernel.org
 S:     Maintained
 
-IDE-SCSI DRIVER
-L:     linux-ide@vger.kernel.org
-L:     linux-scsi@vger.kernel.org
-S:     Orphan
-
 IDLE-I7300
 P:     Andy Henroid
 M:     andrew.d.henroid@intel.com
@@ -2633,13 +2634,13 @@ W:      http://www.hansenpartnership.com/voyager
 S:     Maintained
 
 LINUX FOR POWERPC (32-BIT AND 64-BIT)
-P:     Paul Mackerras
-M:     paulus@samba.org
 P:     Benjamin Herrenschmidt
 M:     benh@kernel.crashing.org
+P:     Paul Mackerras
+M:     paulus@samba.org
 W:     http://www.penguinppc.org/
 L:     linuxppc-dev@ozlabs.org
-T:     git kernel.org:/pub/scm/linux/kernel/git/paulus/powerpc.git
+T:     git kernel.org:/pub/scm/linux/kernel/git/benh/powerpc.git
 S:     Supported
 
 LINUX FOR POWER MACINTOSH
index 1f762189fa64f1f158e6d1d1664cabb14f58264e..c2938e574a40c2de349556430bc83fc0038569c0 100644 (file)
@@ -8,7 +8,6 @@
 #include <asm/uaccess.h>
 
 
-static struct fs_struct init_fs = INIT_FS;
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
 struct mm_struct init_mm = INIT_MM(init_mm);
index 0bbf806253954c1ac42c9f8fd634f1b7e5cfe63c..e859af349467420e3107074cfa94f7d993125c70 100644 (file)
@@ -12,7 +12,6 @@
 
 #include <asm/pgtable.h>
 
-static struct fs_struct init_fs = INIT_FS;
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
 struct mm_struct init_mm = INIT_MM(init_mm);
index 44058469c6ec905c2cad58fca1e315f0b395474c..993d56ee3cf303375a57328680fdc23aa25728f6 100644 (file)
@@ -13,7 +13,6 @@
 
 #include <asm/pgtable.h>
 
-static struct fs_struct init_fs = INIT_FS;
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
 struct mm_struct init_mm = INIT_MM(init_mm);
index 6bdba7b21109e0872c8589d123439335a1073a50..2c228c020978eee16b8edecc047d12689fb1c016 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/mqueue.h>
 #include <linux/fs.h>
 
-static struct fs_struct init_fs = INIT_FS;
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
 
index 5933656db5a2ca58b9a2f583ce5945a57d1b832b..60816e876455112047e21d6191a1a2380aa27dd0 100644 (file)
@@ -37,7 +37,6 @@
  * setup.
  */
 
-static struct fs_struct init_fs = INIT_FS;
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
 struct mm_struct init_mm = INIT_MM(init_mm);
index e2198815b630e5dafd7084ffbac233026fe3ea2f..29429a8b7f6a44b0a6e52629c9b134d0f72317e3 100644 (file)
@@ -10,7 +10,6 @@
 #include <asm/pgtable.h>
 
 
-static struct fs_struct init_fs = INIT_FS;
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
 struct mm_struct init_mm = INIT_MM(init_mm);
index 93a4899e46c23d24923920a85d8977448ad4644e..cb5dc552da97899e4f443b40efd5fae50de4f3f1 100644 (file)
@@ -12,7 +12,6 @@
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 
-static struct fs_struct init_fs = INIT_FS;
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
 struct mm_struct init_mm = INIT_MM(init_mm);
index 9d7e1c66faf403ecfc154dc7597248892b1f38f8..5b0e830c6f33212d48b28ec74f24113f6c1bc5ef 100644 (file)
@@ -17,7 +17,6 @@
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 
-static struct fs_struct init_fs = INIT_FS;
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
 struct mm_struct init_mm = INIT_MM(init_mm);
index 0d658dbb676693f13ef978ae07772951ba75a32c..016885c6f26094b3191fc8f790410d7a99b5c143 100644 (file)
@@ -11,7 +11,6 @@
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 
-static struct fs_struct init_fs = INIT_FS;
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
 struct mm_struct init_mm = INIT_MM(init_mm);
index 3042c2bc8c58490083ef4a2718c6a839c4e7e978..632ce016014d27d6190d1776d86ecaa1503aeca6 100644 (file)
@@ -40,7 +40,6 @@
  * alignment requirements and potentially different initial
  * setup.
  */
-static struct fs_struct init_fs = INIT_FS;
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
 struct mm_struct init_mm = INIT_MM(init_mm);
index 344c01aede08b3e85b1b3f7b0b454ca8ae78d879..fe282de1d596dcb4b93d4077ba8c5fe4c6f3aaee 100644 (file)
@@ -12,7 +12,6 @@
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 
-static struct fs_struct init_fs = INIT_FS;
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
 struct mm_struct init_mm = INIT_MM(init_mm);
index d72487ad7c15526fa79722ad4325c38aa8602ecd..149cd914526e8e2e2d1c407852879cf2111fa822 100644 (file)
@@ -9,7 +9,6 @@
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 
-static struct fs_struct init_fs = INIT_FS;
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
 struct mm_struct init_mm = INIT_MM(init_mm);
index af16f6e5c918870d9545419bcba180fcfe1f9e8f..5ac3566f8c98b62c5a96673665b09f12d5a48696 100644 (file)
@@ -18,7 +18,6 @@
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 
-static struct fs_struct init_fs = INIT_FS;
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
 struct mm_struct init_mm = INIT_MM(init_mm);
index f5941c086551e09c2578821988037dd3628db712..1e25a45d64c17fd48d461489c3f2e950ed29ee53 100644 (file)
@@ -34,7 +34,6 @@
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
 
-static struct fs_struct init_fs = INIT_FS;
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
 struct mm_struct init_mm = INIT_MM(init_mm);
index 4c85b8d564783b7a695aaad977ddd3c96b2ae197..688b329800bd25f559c75f2ea6f0dcdd22ade3b1 100644 (file)
@@ -7,7 +7,6 @@
 #include <linux/mqueue.h>
 #include <asm/uaccess.h>
 
-static struct fs_struct init_fs = INIT_FS;
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
 struct mm_struct init_mm = INIT_MM(init_mm);
index 2949126d28d1f8c9f45bef32d45b96df86f959fa..6b793aeda72ea041ac2a68f1ca2e2ece7f46badc 100644 (file)
@@ -297,7 +297,7 @@ static inline unsigned long fast_get_dcookie(struct path *path)
 {
        unsigned long cookie;
 
-       if (path->dentry->d_cookie)
+       if (path->dentry->d_flags & DCACHE_COOKIE)
                return (unsigned long)path->dentry;
        get_dcookie(path, &cookie);
        return cookie;
index e807168436194c81fe0f4892f9be5a7e4bed685b..7db95c0b86938603176baf5496f23338cd455bc2 100644 (file)
@@ -16,7 +16,6 @@
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 
-static struct fs_struct init_fs = INIT_FS;
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
 struct mm_struct init_mm = INIT_MM(init_mm);
index b151a25cb14de25f455e7ec26eebe124a23b2207..80c35ff71d564d524cf01c752efd0618fa868308 100644 (file)
@@ -7,7 +7,6 @@
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 
-static struct fs_struct init_fs = INIT_FS;
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
 struct pt_regs fake_swapper_regs;
index 62126e4cec54c53c2572a93d3bf4055fe22ba709..f28cb8278e98abb6f2fb79c634b2e74e52cfac84 100644 (file)
@@ -8,7 +8,6 @@
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
 
-static struct fs_struct init_fs = INIT_FS;
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
 struct mm_struct init_mm = INIT_MM(init_mm);
index 910eda8fca188526cf564ec0e35c137079e4c339..806d381947bf1c704dc584e5b29360abb7b40a88 100644 (file)
@@ -10,7 +10,6 @@
 #include "linux/mqueue.h"
 #include "asm/uaccess.h"
 
-static struct fs_struct init_fs = INIT_FS;
 struct mm_struct init_mm = INIT_MM(init_mm);
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
index d39918076bb48a4b70e5b911736f84ec817fd420..df3bf269beab96466785764b619bc737fd0f5d55 100644 (file)
@@ -10,7 +10,6 @@
 #include <asm/pgtable.h>
 #include <asm/desc.h>
 
-static struct fs_struct init_fs = INIT_FS;
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
 struct mm_struct init_mm = INIT_MM(init_mm);
index f6ea94b74da146072cca138aa824ed5a3d5eeec7..74917658b004aea2eb08dca5c5c9ba8a775eb81e 100644 (file)
@@ -170,7 +170,7 @@ static struct irq_cfg irq_cfgx[NR_IRQS] = {
        [15] = { .domain = CPU_MASK_ALL, .vector = IRQ15_VECTOR, },
 };
 
-void __init arch_early_irq_init(void)
+int __init arch_early_irq_init(void)
 {
        struct irq_cfg *cfg;
        struct irq_desc *desc;
@@ -184,6 +184,8 @@ void __init arch_early_irq_init(void)
                desc = irq_to_desc(i);
                desc->chip_data = &cfg[i];
        }
+
+       return 0;
 }
 
 #ifdef CONFIG_SPARSE_IRQ
@@ -212,7 +214,7 @@ static struct irq_cfg *get_one_free_irq_cfg(int cpu)
        return cfg;
 }
 
-void arch_init_chip_data(struct irq_desc *desc, int cpu)
+int arch_init_chip_data(struct irq_desc *desc, int cpu)
 {
        struct irq_cfg *cfg;
 
@@ -224,6 +226,8 @@ void arch_init_chip_data(struct irq_desc *desc, int cpu)
                        BUG_ON(1);
                }
        }
+
+       return 0;
 }
 
 #ifdef CONFIG_NUMA_MIGRATE_IRQ_DESC
@@ -1345,8 +1349,6 @@ void __setup_vector_irq(int cpu)
 
        /* Mark the inuse vectors */
        for_each_irq_desc(irq, desc) {
-               if (!desc)
-                       continue;
                cfg = desc->chip_data;
                if (!cpu_isset(cpu, cfg->domain))
                        continue;
@@ -1730,8 +1732,6 @@ __apicdebuginit(void) print_IO_APIC(void)
        for_each_irq_desc(irq, desc) {
                struct irq_pin_list *entry;
 
-               if (!desc)
-                       continue;
                cfg = desc->chip_data;
                entry = cfg->irq_2_pin;
                if (!entry)
@@ -2378,9 +2378,6 @@ static void ir_irq_migration(struct work_struct *work)
        struct irq_desc *desc;
 
        for_each_irq_desc(irq, desc) {
-               if (!desc)
-                       continue;
-
                if (desc->status & IRQ_MOVE_PENDING) {
                        unsigned long flags;
 
@@ -2670,9 +2667,6 @@ static inline void init_IO_APIC_traps(void)
         * 0x80, because int 0x80 is hm, kind of importantish. ;)
         */
        for_each_irq_desc(irq, desc) {
-               if (!desc)
-                       continue;
-
                cfg = desc->chip_data;
                if (IO_APIC_IRQ(irq) && cfg && !cfg->vector) {
                        /*
index 8655b5bb0963f807a0fe49dcd3da367db19379f0..f99a6c6c432ebc5e53fac79bce694384c2ccdb05 100644 (file)
@@ -435,8 +435,12 @@ static void __init set_highmem_pages_init(void)
 #endif /* !CONFIG_NUMA */
 
 #else
-# define permanent_kmaps_init(pgd_base)                do { } while (0)
-# define set_highmem_pages_init()      do { } while (0)
+static inline void permanent_kmaps_init(pgd_t *pgd_base)
+{
+}
+static inline void set_highmem_pages_init(void)
+{
+}
 #endif /* CONFIG_HIGHMEM */
 
 void __init native_pagetable_setup_start(pgd_t *base)
index 3df469dbe81438c760960cb36a0a4e1d76ff8012..e07f5c9fcd3500727efdd0a734b4cfcf654412fc 100644 (file)
@@ -21,7 +21,6 @@
 
 #include <asm/uaccess.h>
 
-static struct fs_struct init_fs = INIT_FS;
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
 struct mm_struct init_mm = INIT_MM(init_mm);
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 b60d425ce8d1502fcadcfba5350770525d9be2dd..fc8cf7ac7f2bd5a09a176755dbe90f33deca744d 100644 (file)
@@ -485,7 +485,21 @@ static struct dmi_system_id __initdata i8k_dmi_table[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "MP061"),
                },
        },
-       { }
+       {
+               .ident = "Dell Precision",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Precision"),
+               },
+       },
+       {
+               .ident = "Dell Vostro",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Vostro"),
+               },
+       },
+        { }
 };
 
 /*
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--;
-       }
-    &nb