## Automatically generated incremental diff
## From:   linux-2.2.14-pre16
## To:     linux-2.2.14-pre17
## Robot:  $Id: make-incremental-diff,v 1.11 2002/02/20 02:59:33 hpa Exp $

diff -urN linux-2.2.14-pre16/Documentation/devices.txt linux-2.2.14-pre17/Documentation/devices.txt
--- linux-2.2.14-pre16/Documentation/devices.txt	2003-08-15 15:10:00.000000000 -0700
+++ linux-2.2.14-pre17/Documentation/devices.txt	2003-08-15 15:10:02.000000000 -0700
@@ -1,8 +1,7 @@
-
 		       LINUX ALLOCATED DEVICES
 	     Maintained by H. Peter Anvin <hpa@zytor.com>
 
-		   Last revised: December 16, 1999
+		   Last revised: December 21, 1999
 
 This list is the Linux Device List, the official registry of allocated
 device numbers and /dev directory nodes for the Linux operating
@@ -15,7 +14,7 @@
 of this document is no longer maintained.
 
 This document is included by reference into the Filesystem Hierarchy
-Standard (FHS).  The FHS is available from http://www.pathname.com/fhs/.
+Standard (FHS).	 The FHS is available from http://www.pathname.com/fhs/.
 
 Allocations marked (68k/Amiga) apply to Linux/68k on the Amiga
 platform only.	Allocations marked (68k/Atari) apply to Linux/68k on
@@ -199,7 +198,7 @@
 
 		Older versions of the Linux kernel used this major
 		number for BSD PTY devices.  As of Linux 2.1.115, this
-		is no longer supported.  Use major numbers 2 and 3.
+		is no longer supported.	 Use major numbers 2 and 3.
 
   5 char	Alternate TTY devices
 		  0 = /dev/tty		Current TTY device
@@ -305,6 +304,8 @@
 		  7 = /dev/amigamouse1	Second Amiga mouse
 		  8 = /dev/smouse	Simple serial mouse driver
 		  9 = /dev/pc110pad	IBM PC-110 digitizer pad
+		 10 = /dev/adbmouse	Apple Desktop Bus mouse
+		 11 = /dev/vrtpanel	Vr41xx embedded touch panel
 		128 = /dev/beep		Fancy beep device
 		129 = /dev/modreq	Kernel module load request
 		130 = /dev/watchdog	Watchdog timer port
@@ -353,6 +354,7 @@
 		177 = /dev/cbm		Serial CBM bus
 		178 = /dev/jsflash	JavaStation OS flash SIMM
 		179 = /dev/xsvc		High-speed shared-mem/semaphore service
+		180 = /dev/vrbuttons	Vr41xx button input device
 		240-255			Reserved for local use
 
  11 char	Raw keyboard device
@@ -570,7 +572,7 @@
 		 16 = /dev/zqft0	Unit 0, rewind-on-close, compression
 		 17 = /dev/zqft1	Unit 1, rewind-on-close, compression
 		 18 = /dev/zqft2	Unit 2, rewind-on-close, compression
-		 19 = /dev/zqtf3	Unit 3, rewind-on-close, compression
+		 19 = /dev/zqft3	Unit 3, rewind-on-close, compression
 		 20 = /dev/nzqft0	Unit 0, no rewind-on-close, compression
 		 21 = /dev/nzqft1	Unit 1, no rewind-on-close, compression
 		 22 = /dev/nzqft2	Unit 2, no rewind-on-close, compression
@@ -1356,8 +1358,8 @@
 
 
  89 char	I2C bus interface
-		  0 = /dev/i2c0		First I2C adapter
-		  1 = /dev/i2c1		Second I2C adapter
+		  0 = /dev/i2c-0	First I2C adapter
+		  1 = /dev/i2c-1	Second I2C adapter
 		    ...
 
     block	Eighth IDE hard disk/CD-ROM interface
@@ -1735,9 +1737,9 @@
 		 63 = /dev/ttyCH63	AT/PCI-Fast board 3, port 15
 
 165 char	Chase Research AT/PCI-Fast serial card - alternate devices
-		  0 = /dev/cuch0	Callout device corresponding to ttyCH0
+		  0 = /dev/cuch0	Callout device for ttyCH0
 		    ...
-		 63 = /dev/cuch63	Callout device corresponding to ttyCH63
+		 63 = /dev/cuch63	Callout device for ttyCH63
 
 166 char	ACM USB modems
 		  0 = /dev/ttyACM0	First ACM modem
@@ -1796,13 +1798,13 @@
 		    ...
 
 177 char	TI PCILynx memory spaces
-		  0 = /dev/pcilynx/aux0  AUX space of first PCILynx card
+		  0 = /dev/pcilynx/aux0	 AUX space of first PCILynx card
 		    ...
 		 15 = /dev/pcilynx/aux15 AUX space of 16th PCILynx card
-		 16 = /dev/pcilynx/rom0  ROM space of first PCILynx card
+		 16 = /dev/pcilynx/rom0	 ROM space of first PCILynx card
 		    ...
 		 31 = /dev/pcilynx/rom15 ROM space of 16th PCILynx card
-		 32 = /dev/pcilynx/ram0  RAM space of first PCILynx card
+		 32 = /dev/pcilynx/ram0	 RAM space of first PCILynx card
 		    ...
 		 47 = /dev/pcilynx/ram15 RAM space of 16th PCILynx card
 
@@ -1836,7 +1838,7 @@
 		    ...
 
 182 char	Picture Elements THR2 binarizer
-		  0 = /dev/pethr0       First THR2 board
+		  0 = /dev/pethr0	First THR2 board
 		  1 = /dev/pethr1	Second THR2 board
 		    ...
 
@@ -1870,11 +1872,16 @@
 		    ...
 
 189 char	USB serial converters - alternate devices
-		  0 = /dev/cuusb0	Callout device corresponding to ttyUSB0
-		  1 = /dev/cuusb1	Callout device corresponding to ttyUSB1
+		  0 = /dev/cuusb0	Callout device for ttyUSB0
+		  1 = /dev/cuusb1	Callout device for ttyUSB1
+		    ...
+
+190 char	Kansas City tracker/tuner card
+		  0 = /dev/kctt0	First KCT/T card
+		  1 = /dev/kctt1	Second KCT/T card
 		    ...
 
-190-239		UNALLOCATED
+191-239		UNALLOCATED
 
 240-254		LOCAL/EXPERIMENTAL USE
 
@@ -1983,7 +1990,7 @@
 starting at /dev/tty1; /dev/tty0 is the current virtual console.
 /dev/tty0 is the device that should be used to access the system video
 card on those architectures for which the frame buffer devices
-(/dev/fb*) are not applicable.  Do not use /dev/console
+(/dev/fb*) are not applicable.	Do not use /dev/console
 for this purpose.
 
 The console device, /dev/console, is the device to which system
@@ -2000,10 +2007,10 @@
 one, either in hardware (such as internal modems) or in software (such
 as the ISDN driver.)  Under Linux, each serial ports has two device
 names, the primary or callin device and the alternate or callout one.
-Each kind of device is indicated by a different letter.  For any
+Each kind of device is indicated by a different letter.	 For any
 letter X, the names of the devices are /dev/ttyX# and /dev/cux#,
 respectively; for historical reasons, /dev/ttyS# and /dev/ttyC#
-correspond to /dev/cua# and /dev/cub#.  In the future, it should be
+correspond to /dev/cua# and /dev/cub#.	In the future, it should be
 expected that multiple letters will be used; all letters will be upper
 case for the "tty" device (e.g. /dev/ttyDP#) and lower case for the
 "cu" device (e.g. /dev/cudp#).
@@ -2017,7 +2024,7 @@
 removed from a future version of Linux.
 
 Arbitration of serial ports is provided by the use of lock files with
-the names /var/lock/LCK..ttyX#.  The contents of the lock file should
+the names /var/lock/LCK..ttyX#.	 The contents of the lock file should
 be the PID of the locking process as an ASCII number.
 
 It is common practice to install links such as /dev/modem
@@ -2025,7 +2032,7 @@
 presence of these links, it is recommended that software chase
 symlinks and lock all possible names; additionally, it is recommended
 that a lock file be installed with the corresponding alternate
-device.  In order to avoid deadlocks, it is recommended that the locks
+device.	 In order to avoid deadlocks, it is recommended that the locks
 are acquired in the following order, and released in the reverse:
 
 	1. The symbolic link name, if any (/var/lock/LCK..modem)
@@ -2045,7 +2052,7 @@
 
 Pseudoterminals, or PTYs, are used to create login sessions or provide
 other capabilities requiring a TTY line dicipline (including SLIP or
-PPP capability) to arbitrary data-generation processes.  Each PTY has
+PPP capability) to arbitrary data-generation processes.	 Each PTY has
 a master side, named /dev/pty[p-za-e][0-9a-f], and a slave side, named
 /dev/tty[p-za-e][0-9a-f].  The kernel arbitrates the use of PTYs by
 allowing each master side to be opened only once.
diff -urN linux-2.2.14-pre16/Documentation/knfsd.txt linux-2.2.14-pre17/Documentation/knfsd.txt
--- linux-2.2.14-pre16/Documentation/knfsd.txt	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.2.14-pre17/Documentation/knfsd.txt	2003-08-15 15:10:02.000000000 -0700
@@ -0,0 +1,98 @@
+This is the Linux NFS utility package version 0.1.5. It is based on
+knfsd 1.4.7.
+
+WARNING: The NFS servers in Linux 2.2 to 2.2.13 are not compatible with
+other NFS client implemenations. If you plan to use Linux 2.2.x as an
+NFS server for non-Linux NFS clients, you should get the Linux NFS
+kernel from the Linux NFS CVS server:
+
+1. Set the environment variable, CVS_RSH, to ssh.
+2. Login to the Linux NFS CVS server:
+
+# cvs -z 3 -d:pserver:anonymous@cvs.linuxnfs.sourceforge.org:/cvsroot/nfs login
+
+without password if it is your first time.
+
+3. Check out the current Linux 2.2 NFS kernel:
+
+a. From the NFS V2 branch:
+
+# cvs -z 3 -d:pserver:anonymous@cvs.linuxnfs.sourceforge.org:/cvsroot/nfs co -r linux-2-2-nfsv2 linux-2.2
+
+b. From the main trunk:
+
+# cvs -z 3 -d:pserver:anonymous@cvs.linuxnfs.sourceforge.org:/cvsroot/nfs co linux-2.2
+
+4. If you don't want to use the current NFS kernel, you can find out
+for which kernels the NFS patch is available:
+
+# cd linux-2.2
+# cvs -z 9 -d:pserver:anonymous@cvs.linuxnfs.sourceforge.org:/cvsroot/nfs status -v Makefile
+
+Then generate the kernel patch:
+
+# cvs -z 3 -d:pserver:anonymous@cvs.linuxnfs.sourceforge.org:/cvsroot/nfs rdiff -ko -u -r linux-2-2-xx -r linux-2-2-xx-nfsv2-xxxxx linux-2.2
+
+If there is no NFS patch for the kernel you are interested in, you have
+to make a patch closest to your kernel version and apply it by hand.
+
+There is a Linux NFS kernel source tree for Linux 2.3, linux-2.3, on
+the Linux NFS CVS server. We will need all the help we can get. To
+contribute to the Linux NFS project, please go to
+
+http://www.linuxnfs.sourceforge.org
+
+You register yourself. Please send an email to
+nfs-admin@linuxnfs.sourceforge.org with
+
+1. Your user id on www.linuxnfs.sourceforge.org.
+2. The area in NFS you'd like to work on.
+
+You will be notified when it is done.
+
+There is a Linux NFS mailing list at
+
+http://lists.sourceforge.net/mailman/listinfo/nfs/                                                               
+You can subscribe it and search the mailing list archive via a web
+browser.
+
+The nfs-utils package is available from the CVS server:
+
+# cvs -z 3 -d:pserver:anonymous@cvs.linuxnfs.sourceforge.org:/cvsroot/nfs co nfs-utils
+
+will get the latest version.
+
+The files are
+
+ftp://ftp.linuxnfs.sourceforge.org/pub/nfs/nfs-utils-0.1.5.tar.gz
+ftp://ftp.linuxnfs.sourceforge.org/pub/nfs/nfs-utils-0.1.4-0.1.5.diff.gz
+
+To compile, just do
+
+# ./configure
+# make
+
+# make install
+
+will install the nfs-utils binaries. You have to install the NFS
+service scripts. There are 2 in etc/redhat provided for RedHat 6.x.
+They are tested on RedHat 6.1.
+
+On RedHat 6.1, you can use
+
+# rpm -ta nfs-utils-0.1.5.tar.gz
+
+to build the source and binary RPMs.
+
+If your mount from util-linux is too old, you will need 2 patches:
+
+ftp://ftp.linuxnfs.sourceforge.org/pub/nfs/util-linux-2.9o-mount-nfsv3.patch
+ftp://ftp.linuxnfs.sourceforge.org/pub/nfs/util-linux-2.9w-mount-nfsv3try.patch
+
+Thanks.
+
+
+H.J.
+hjl@lucon.org
+12/19/99
+
diff -urN linux-2.2.14-pre16/Documentation/moxa-smartio linux-2.2.14-pre17/Documentation/moxa-smartio
--- linux-2.2.14-pre16/Documentation/moxa-smartio	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.2.14-pre17/Documentation/moxa-smartio	2003-08-15 15:10:02.000000000 -0700
@@ -0,0 +1,412 @@
+=============================================================================
+
+	MOXA Smartio Family Device Driver Ver 1.1 Installation Guide
+		    for Linux Kernel 2.2.x and 2.0.3x
+	       Copyright (C) 1999, Moxa Technologies Co, Ltd.
+=============================================================================
+Content
+
+1. Introduction
+2. System Requirement
+3. Installation
+4. Utilities
+5. Setserial
+6. Troubleshooting
+
+-----------------------------------------------------------------------------
+1. Introduction
+
+   The Smartio family Linux driver, Ver. 1.1, supports following multiport
+   boards.
+
+    -C104P/H/HS, C104H/PCI, C104HS/PCI, CI-104J 4 port multiport board.
+    -C168P/H/HS, C168H/PCI 8 port multiport board.
+
+   This driver has been modified a little and cleaned up from the Moxa
+   contributed driver code and merged into Linux 2.2.14pre. In paticular
+   official major/minor numbers have been assigned which are different to
+   those the original Moxa supplied driver used.
+
+   This driver and installation procedure have been developed upon Linux Kernel
+   2.2.5 and backward compatible to 2.0.3x. This driver supports Intel x86 and
+   Alpha hardware platform. In order to maintain compatibility, this version
+   has also been properly tested with RedHat, OpenLinux, TurboLinux and
+   S.u.S.E Linux. However, if compatibility problem occurs, please contact
+   Moxa at support@moxa.com.tw.
+
+   In addition to device driver, useful utilities are also provided in this
+   version. They are
+    - msdiag     Diagnostic program for detecting installed Moxa Smartio boards.
+    - msmon      Monitor program to observe data count and line status signals.
+    - msterm     A simple terminal program which is useful in testing serial
+	         ports.
+    - io-irq.exe Configuration program to setup ISA boards. Please note that
+                 this program can only be executed under DOS.
+
+   All the drivers and utilities are published in form of source code under
+   GNU General Public License in this version. Please refer to GNU General
+   Public License announcement in each source code file for more detail.
+
+   In Moxa's ftp sites, you may always find latest driver at
+   ftp://ftp.moxa.com  or ftp://ftp.moxa.com.tw.
+
+   This version of driver can be installed as Loadable Module (Module driver)
+   or built-in into kernel (Static driver). You may refer to following
+   installation procedure for suitable one. Before you install the driver,
+   please refer to hardware installation procedure in the User's Manual.
+
+   We assume the user should be familiar with following documents.
+   - Serial-HOWTO
+   - Kernel-HOWTO
+
+-----------------------------------------------------------------------------
+2. System Requirement
+   - Hardware platform: Intel x86 or Alpha machine
+   - Kernel version: 2.0.3x or 2.2.x
+   - gcc version 2.72 or later
+   - Maximum 4 boards can be installed in combination
+
+-----------------------------------------------------------------------------
+3. Installation
+
+   3.1 Hardware installation
+
+       There are two types of buses, ISA and PCI, for Smartio family multiport
+       board.
+
+       ISA board
+       ---------
+       You'll have to configure CAP address, I/O address, Interrupt Vector
+       as well as IRQ before installing this driver. Please refer to hardware
+       installation procedure in User's Manual before proceed any further.
+       Please make sure the JP1 is open after the ISA board is set properly.
+
+       PCI board
+       ---------
+       You may need to adjust IRQ useage in BIOS to avoid from IRQ conflict
+       with other ISA devices. Please refer to hardware installation
+       procedure in User's Manual in advance.
+
+       IRQ Sharing
+       -----------
+       Each port within the same multiport board shares the same IRQ. Up to
+       4 Moxa Smartio Family multiport boards can be installed together on
+       one system and they can share the same IRQ.
+
+   3.2 Driver files and device naming convention
+
+       The driver file may be obtained from ftp, CD-ROM or floppy disk. The
+       first step, anyway, is to copy driver file "mxser.tgz" into specified
+       directory. e.g. /moxa. The execute commands as below.
+
+       # cd /moxa
+       # tar xvf /dev/fd0 
+       or
+       # cd /moxa
+       # cp /mnt/cdrom/<driver directory>/mxser.tgz .
+       # tar xvfz mxser.tgz
+
+       You may find all the driver and utilities files in /moxa/mxser.
+       Following installation procedure depends on the model you'd like to
+       run the driver. If you prefer module driver, please refer to 3.3.
+       If static driver is required, please refer to 3.4.
+
+       Dialin and callout port
+       -----------------------
+       This driver remains traditional serial device properties. There're
+       two special file name for each serial port. One is dial-in port
+       which is named "ttyMxx". For callout port, the naming convention
+       is "cumxx".
+
+       Device naming when more than 2 boards installed
+       -----------------------------------------------
+       Naming convention for each Smartio multiport board is pre-defined
+       as below.
+
+       Board Num.	 Dial-in Port	      Callout port
+       1st board	ttyM0  - ttyM7	      cum0  - cum7
+       2nd board	ttyM8  - ttyM15       cum8  - cum15
+       3rd board	ttyM16 - ttyM23       cum16 - cum23
+       4th board	ttyM24 - ttym31       cum24 - cum31
+
+       Board sequence
+       --------------
+       This driver will activate ISA boards according to the parameter set
+       in the driver. After all specified ISA board activated, PCI board
+       will be installed in the system automatically driven.
+       Therefore the board number is sorted by the CAP address of ISA boards.
+       For PCI boards, their sequence will be after ISA boards and C168H/PCI
+       has higher priority than C104H/PCI boards.
+
+   3.3 Module driver configuration
+       Module driver is easiest way to install. If you prefer static driver
+       installation, please skip this paragraph.
+       1. Find "Makefile" in /moxa/mxser, then run
+
+	  # make install
+
+	  The driver files "mxser.o" and utilities will be properly compiled
+	  and copied to system directories respectively.Then run
+
+	  # insmod mxser
+
+	  to activate the moduler driver. You may run "lsmod" to check
+	  if "mxser.o" is activated.
+
+       2. Create special files by executing "msmknod".
+	  # cd /moxa/mxser/driver
+	  # ./msmknod
+
+	  Default major numbers for dial-in device and callout device are
+	  174, 175. Msmknod will delete any special files occuping the same
+	  device naming.
+
+       3. Up to now, you may manually execute "insmod mxser" to activate
+	  this driver and run "rmmod mxser" to remove it. However, it's
+	  better to have a boot time configuration to eliminate manual
+	  operation.
+	  Boot time configuration can be achieved by rc file. Run following
+	  command for setting rc files.
+
+	  # cd /moxa/mxser/driver
+	  # cp ./rc.mxser /etc/rc.d
+	  # cd /etc/rc.d
+
+	  You may have to modify part of the content in rc.mxser to specify
+          parameters for ISA board. Please refer to rc.mxser for more detail.
+          Find "rc.serial". If "rc.serial" doesn't exist, create it by vi.
+	  Add "rc.mxser" in last line. Next, open rc.local by vi
+	  and append following content.
+
+	  if [ -f /etc/rc.d/rc.serial ]; then
+	     sh /etc/rc.d/rc.serial
+	  fi
+
+       4. Reboot and check if mxser.o activated by "lsmod" command.
+       5. If you'd like to drive Smartio ISA boards in the system, you'll
+	  have to add parameter to specify CAP address of given board while
+          activating "mxser.o". The format for parameters are as follows.
+
+	  insmod mxser ioaddr=0x???,0x???,0x???,0x???
+				|      |     |	  |
+				|      |     |	  +- 4th ISA board
+				|      |     +------ 3rd ISA board
+				|      +------------ 2nd ISA board
+				+------------------- 1st ISA board
+
+   3.4 Static driver configuration
+
+       1. Create link
+	  # cd /usr/src/linux/drivers/char
+	  # ln -s /moxa/mxser/driver/mxser.c mxser.c
+
+       2. Add CAP address list for ISA boards
+	  In module mode, the CAP address for ISA board is given by
+	  parameter. In static driver configuration, you'll have to
+	  assign it within driver's source code. If you will not
+	  install any ISA boards, you may skip to next portion.
+	  The instructions to modify driver source code are as
+	  below.
+	  a. # cd /moxa/mxser/driver
+	     # vi mxser.c
+	  b. Find the array mxserBoardCAP[] as belows.
+
+	     static int mxserBoardCAP[]
+	     = {0x00, 0x00, 0x00, 0x00};
+
+	  c. Change the address within this array using vi. For
+	     example, to driver 2 ISA boards with CAP address
+	     0x280 and 0x180 as 1st and 2nd board. Just to change
+	     the source code as follows.
+
+	     static int mxserBoardCAP[]
+	     = {0x280, 0x180, 0x00, 0x00};
+
+       3. Modify tty_io.c
+	  # cd /usr/src/linux/drivers/char/
+	  # vi tty_io.c
+	    Find pty_init(), insert "mxser_init()" as
+
+	    pty_init();
+	    mxser_init();
+
+       4. Modify tty.h
+	  # cd /usr/src/linux/include/linux
+	  # vi tty.h
+	    Find extern int tty_init(void), insert "mxser_init()" as
+
+	    extern int tty_init(void);
+	    extern int mxser_init(void);
+     
+       5. Modify Makefile
+	  # cd /usr/src/linux/drivers/char
+	  # vi Makefile
+	    Find L_OBJS := tty_io.o ...... random.o, add
+	    "mxser.o" at last of this line as
+	    L_OBJS := tty_io.o ....... mxser.o
+
+       6. Rebuild kernel
+	  The following are for Linux kernel rebuilding,for your reference only.
+	  For appropriate details, please refer to the Linux document.
+
+	  If 'lilo' utility is installed, please use 'make zlilo' to rebuild
+	  kernel. If 'lilo' is not installed, please follow the following steps.
+
+	   a. cd /usr/src/linux
+	   b. make clean			     /* take a few minutes */
+	   c. make dep				     /* take a few minutes */
+	   d. make bzImage		   /* take probably 10-20 minutes */
+	   e. Backup original boot kernel.		  /* optional step */
+	   f. cp /usr/src/linux/arch/i386/boot/bzImage /boot/vmlinuz
+	   g. Please make sure the boot kernel (vmlinuz) is in the
+	      correct position. If you use 'lilo' utility, you should
+	      check /etc/lilo.conf 'image' item specifiedd the path
+	      which is the 'vmlinuz' path, or you will load wrong
+	      (or old) boot kernel image (vmlinuz).
+	   h. chmod 400 /vmlinuz
+	   i. lilo
+	   j. rdev -R /vmlinuz 1
+	   k. sync
+
+	  Note that if the result of "make zImage" is ERROR, then you have to
+	  go back to Linux configuration Setup. Type "make config" in directory
+	  /usr/src/linux or "setup".
+
+	  Since system include file, /usr/src/linux/include/linux/interrupt.h,
+	  is modified each time the MOXA driver is installed, kernel rebuilding
+	  is inevitable. And it takes about 10 to 20 minutes depends on the
+	  machine.
+
+       7. Make utility
+	  # cd /moxa/mxser/utility
+	  # make install
+       
+       8. Make special file
+          # cd /moxa/mxser/driver
+          # ./msmknod
+
+       9. Reboot
+
+   3.5 Custom configuration
+       Although this driver already provides you default configuration, you
+       still can change the device name and major number.The instruction to
+       change these parameters are shown as below.
+
+       Change Device name
+       ------------------
+       If you'd like to use other device names instead of default naming
+       convention, all you have to do is to modify the internal code
+       within the shell script "msmknod". First, you have to open "msmknod"
+       by vi. Locate each line contains "ttyM" and "cum" and change them
+       to the device name you desired. "msmknod" creates the device names
+       you need next time executed.
+
+       Change Major number
+       -------------------
+       If major number 30 and 35 had been occupied, you may have to select
+       2 free major numbers for this driver. There are 3 steps to change
+       major numbers.
+
+       1. Find free major numbers
+	  In /proc/devices, you may find all the major numbers occupied
+	  in the system. Please select 2 major numbers that are available.
+	  e.g. 40, 45.
+       2. Create special files
+	  Run /moxa/mxser/driver/msmknod to create special files with
+	  specified major numbers.
+       3. Modify driver with new major number
+	  Run vi to open /moxa/mxser/driver/mxser.c. Locate the line
+	  contains "MXSERMAJOR". Change the content as below.
+	  #define	  MXSERMAJOR		  40
+	  #define	  MXSERCUMAJOR		  45
+       4. Run # make install in /moxa/mxser/driver.
+
+   3.6 Verify driver installation
+       You may refer to /var/log/messages to check the latest status
+       log reported by this driver whenever it's activated.
+-----------------------------------------------------------------------------
+4. Utilities
+   There are 3 utilities contained in this driver. They are msdiag, msmon and
+   msterm. These 3 utilities are released in form of source code. They should
+   be compiled into executable file and copied into /usr/bin.
+
+   msdiag - Diagnostic
+   --------------------
+   This utility provides the function to detect what Moxa Smartio multiport
+   board exists in the system.
+
+   msmon - Port Monitoring
+   -----------------------
+   This utility gives the user a quick view about all the MOXA ports'
+   activities. One can easily learn each port's total received/transmitted
+   (Rx/Tx) character count since the time when the monitoring is started.
+   Rx/Tx throughputs per second are also reported in interval basis (e.g.
+   the last 5 seconds) and in average basis (since the time the monitoring
+   is started). You can reset all ports' count by <HOME> key. <+> <->
+   (plus/minus) keys to change the displaying time interval. Press <ENTER>
+   on the port, that cursor stay, to view the port's communication
+   parameters, signal status, and input/output queue.
+
+   msterm - Terminal Emulation
+   ---------------------------
+   This utility provides data sending and receiving ability of all tty ports,
+   especially for MOXA ports. It is quite useful for testing simple
+   application, for example, sending AT command to a modem connected to the
+   port or used as a terminal for login purpose. Note that this is only a
+   dumb terminal emulation without handling full screen operation.
+-----------------------------------------------------------------------------
+5. Setserial
+
+   Supported Setserial parameters are listed as below.
+
+   uart 	  set UART type(16450-->disable FIFO, 16550A-->enable FIFO)
+   close_delay	  set the amount of time(in 1/100 of a second) that DTR
+		  should be kept low while being closed.
+   closing_wait   set the amount of time(in 1/100 of a second) that the
+		  serial port should wait for data to be drained while
+		  being closed, before the receiver is disable.
+   spd_hi	  Use  57.6kb  when  the application requests 38.4kb.
+   spd_vhi	  Use  115.2kb	when  the application requests 38.4kb.
+   spd_normal	  Use  38.4kb  when  the application requests 38.4kb.
+
+-----------------------------------------------------------------------------
+6. Troubleshooting
+
+   The boot time error mesages and solutions are stated as clearly as
+   possible. If all the possible solutions fail, please contact our technical
+   support team to get more help.
+
+   Error msg: More than 4 Moxa Smartio family boards found. Fifth board and
+	      after are ignored.
+   Solution:
+   To avoid this problem, please unplug fifth and after board, because Moxa
+   driver supports up to 4 boards.
+
+   Error msg: Request_irq fail, IRQ(?) may be conflict with another device.
+   Solution:
+   Other PCI or ISA devices occupy the assigned IRQ. If you are not sure
+   which device causes the situation,please check /proc/interrupts to find
+   free IRQ and simply change another free IRQ for Moxa board.
+
+   Error msg: Board #: C1xx Series(CAP=xxx) interupt number invalid.
+   Solution:
+   Each port within the same multiport board shares the same IRQ. Please set
+   one IRQ (IRQ doesn't equal to zero) for one Moxa board.
+
+   Error msg: No interrupt vector be set for Moxa ISA board(CAP=xxx).
+   Solution:
+   Moxa ISA board needs an interrupt vector.Please refer to user's manual
+   "Hardware Installation" chapter to set interrupt vector.
+
+   Error msg: Couldn't install MOXA Smartio family driver!
+   Solution:
+   Load Moxa driver fail, the major number may conflict with other devices.
+   Please refer to previous section 3.5 to change a free major number for
+   Moxa driver.
+
+   Error msg: Couldn't install MOXA Smartio family callout driver!
+   Solution:
+   Load Moxa callout driver fail, the callout device major number may
+   conflict with other devices. Please refer to previous section 3.5 to
+   change a free callout device major number for Moxa driver.
+-----------------------------------------------------------------------------
diff -urN linux-2.2.14-pre16/Documentation/networking/sis900.txt linux-2.2.14-pre17/Documentation/networking/sis900.txt
--- linux-2.2.14-pre16/Documentation/networking/sis900.txt	2003-08-15 15:10:00.000000000 -0700
+++ linux-2.2.14-pre17/Documentation/networking/sis900.txt	2003-08-15 15:10:02.000000000 -0700
@@ -1,6 +1,6 @@
   SiS 900/7016 Fast Ethernet Device Driver
   by Ollie Lho (ollie@sis.com.tw)
-  November 4, 1999. Document Revision: 0.1
+  November 4, 1999. Document Revision: 0.2
 
   This document gives some information on installation and usage of SiS
   900/7016 device driver under Linux.
@@ -17,7 +17,7 @@
 
   4. Tested Environment
 
-  5. Files in This Rackage
+  5. Files in This Package
 
   6. Installation
 
@@ -111,9 +111,11 @@
 
   9. Names of variables were changed to be more consistent.
 
- 10. Clean up of auo-negotiation and timer code.
+  10.
+     Clean up of auo-negotiation and timer code.
 
- 11. Automatic detection and change of PHY on the fly.
+  11.
+     Automatic detection and change of PHY on the fly.
 
 
   4.  Tested Environment
@@ -137,7 +139,7 @@
   o  Samba version 2.0.3
 
 
-  5.  Files in This Rackage
+  5.  Files in This Package
 
   In the package you can find these files:
 
@@ -157,10 +159,16 @@
 
   6.  Installation
 
-  Before trying to install the driver, be sure to get the latest
-  revision from SiS' Home Page.  If you have no prior experience in
-  networking under Linux, please read Ethernet HOWTO and Networking
-  HOWTO available from Linux Documentation Project (LDP).
+  Silicon Integrated System Corp. is cooperating closely with core Linux
+  Kernel developers. The revisions of SiS 900 driver are distributed by
+  the usuall channels for kernel tar files and patches. Those kernel tar
+  files for official kernel and patches for kernel pre-release can be
+  download at official kernel ftp site
+  <http://ftp.kernel.org/pub/linux/kernel/> and its mirrors.  The 1.06
+  revision can be found in kernel version later than 2.3.15 and
+  pre-2.2.14.  If you have no prior experience in networking under
+  Linux, please read Ethernet HOWTO and Networking HOWTO available from
+  Linux Documentation Project (LDP).
 
   The installation procedure are different according to your kernel
   versions.
@@ -244,6 +252,7 @@
        sis900.c: v1.06  11/04/99
        eth0: SiS 900 PCI Fast Ethernet at 0xd000, IRQ 10, 00:00:e8:83:7f:a4.
        eth0: SiS 900 Internal MII PHY transceiver found at address 1.
+       eth0: Using SiS 900 Internal MII PHY as default
 
 
 
@@ -269,7 +278,6 @@
 
 
 
-       eth0: Using SiS 900 Internal MII PHY as default
        eth0: Media Link On 100mbps full-duplex
 
 
diff -urN linux-2.2.14-pre16/Documentation/README.moxa linux-2.2.14-pre17/Documentation/README.moxa
--- linux-2.2.14-pre16/Documentation/README.moxa	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.2.14-pre17/Documentation/README.moxa	2003-08-15 15:10:02.000000000 -0700
@@ -0,0 +1,18 @@
+ ===================================================================	
+ Release Note of Linux Driver for Moxa's C104/C168/CI-104J
+ ===================================================================	
+
+ -------------------------------------------------------------------
+ Ver. 1.1  				               Sep.  1, 1999
+ -------------------------------------------------------------------
+ 1. Improved:
+   a. Static driver (kernel) and dynamic driver (loadable module) 
+      modes are supported.
+   b. Multiple Smartio PCI series boards sharing the same IRQ 
+      supported.
+
+ -------------------------------------------------------------------
+ Ver. 1.0  				               Feb  17, 1997
+ -------------------------------------------------------------------
+ 1. Newly release.
+
diff -urN linux-2.2.14-pre16/drivers/block/ide.c linux-2.2.14-pre17/drivers/block/ide.c
--- linux-2.2.14-pre16/drivers/block/ide.c	2003-08-15 15:10:01.000000000 -0700
+++ linux-2.2.14-pre17/drivers/block/ide.c	2003-08-15 15:10:02.000000000 -0700
@@ -1146,7 +1146,7 @@
  * the driver.  This makes the driver much more friendlier to shared IRQs
  * than previous designs, while remaining 100% (?) SMP safe and capable.
  */
-static void ide_do_request (ide_hwgroup_t *hwgroup)
+static void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
 {
 	struct blk_dev_struct *bdev;
 	ide_drive_t	*drive;
@@ -1204,11 +1204,15 @@
 		if (bdev->current_request == &bdev->plug)	/* FIXME: paranoia */
 			printk("%s: Huh? nuking plugged queue\n", drive->name);
 		bdev->current_request = hwgroup->rq = drive->queue;
+		if (hwif->irq != masked_irq)
+			disable_irq_nosync(hwif->irq);
 		spin_unlock(&io_request_lock);
 		if (!hwif->serialized)	/* play it safe with buggy hardware */
 			ide__sti();
 		startstop = start_request(drive);
 		spin_lock_irq(&io_request_lock);
+		if (hwif->irq != masked_irq)
+			enable_irq(hwif->irq);
 		if (startstop == ide_stopped)
 			hwgroup->busy = 0;
 	}
@@ -1226,41 +1230,41 @@
 
 void do_ide0_request (void)
 {
-	ide_do_request (ide_hwifs[0].hwgroup);
+	ide_do_request (ide_hwifs[0].hwgroup, 0);
 }
 
 #if MAX_HWIFS > 1
 void do_ide1_request (void)
 {
-	ide_do_request (ide_hwifs[1].hwgroup);
+	ide_do_request (ide_hwifs[1].hwgroup, 0);
 }
 #endif /* MAX_HWIFS > 1 */
 
 #if MAX_HWIFS > 2
 void do_ide2_request (void)
 {
-	ide_do_request (ide_hwifs[2].hwgroup);
+	ide_do_request (ide_hwifs[2].hwgroup, 0);
 }
 #endif /* MAX_HWIFS > 2 */
 
 #if MAX_HWIFS > 3
 void do_ide3_request (void)
 {
-	ide_do_request (ide_hwifs[3].hwgroup);
+	ide_do_request (ide_hwifs[3].hwgroup, 0);
 }
 #endif /* MAX_HWIFS > 3 */
 
 #if MAX_HWIFS > 4
 void do_ide4_request (void)
 {
-	ide_do_request (ide_hwifs[4].hwgroup);
+	ide_do_request (ide_hwifs[4].hwgroup, 0);
 }
 #endif /* MAX_HWIFS > 4 */
 
 #if MAX_HWIFS > 5
 void do_ide5_request (void)
 {
-	ide_do_request (ide_hwifs[5].hwgroup);
+	ide_do_request (ide_hwifs[5].hwgroup, 0);
 }
 #endif /* MAX_HWIFS > 5 */
 
@@ -1328,7 +1332,7 @@
 				hwgroup->busy = 0;
 		}
 	}
-	ide_do_request(hwgroup);
+	ide_do_request(hwgroup, 0);
 	spin_unlock_irqrestore(&io_request_lock, flags);
 }
 
@@ -1471,7 +1475,7 @@
 	if (startstop == ide_stopped) {
 		if (hwgroup->handler == NULL) {	/* paranoia */
 			hwgroup->busy = 0;
-			ide_do_request(hwgroup);
+			ide_do_request(hwgroup, hwif->irq);
 		} else {
 			printk("%s: ide_intr: huh? expected NULL handler on exit\n", drive->name);
 		}
@@ -1574,7 +1578,7 @@
 		rq->next = cur_rq->next;
 		cur_rq->next = rq;
 	}
-	ide_do_request(hwgroup);
+	ide_do_request(hwgroup, 0);
 	spin_unlock_irqrestore(&io_request_lock, flags);
 	if (action == ide_wait) {
 		down(&sem);			/* wait for it to be serviced */
diff -urN linux-2.2.14-pre16/drivers/block/ide-probe.c linux-2.2.14-pre17/drivers/block/ide-probe.c
--- linux-2.2.14-pre16/drivers/block/ide-probe.c	2003-08-15 15:10:01.000000000 -0700
+++ linux-2.2.14-pre17/drivers/block/ide-probe.c	2003-08-15 15:10:02.000000000 -0700
@@ -399,7 +399,7 @@
 				drive->present = 1;
 			} else
 				printk("hd%d: C/H/S=%d/%d/%d from BIOS ignored\n",
-				       cyl, head, sect);
+				       unit, cyl, head, sect);
 		}
 		BIOS += 16;
 	}
diff -urN linux-2.2.14-pre16/drivers/char/Config.in linux-2.2.14-pre17/drivers/char/Config.in
--- linux-2.2.14-pre16/drivers/char/Config.in	2003-08-15 15:10:01.000000000 -0700
+++ linux-2.2.14-pre17/drivers/char/Config.in	2003-08-15 15:10:02.000000000 -0700
@@ -22,30 +22,32 @@
 fi
 bool 'Non-standard serial port support' CONFIG_SERIAL_NONSTANDARD
 if [ "$CONFIG_SERIAL_NONSTANDARD" = "y" ]; then
+   tristate 'Computone IntelliPort Plus serial support' CONFIG_COMPUTONE
    tristate 'Comtrol Rocketport support' CONFIG_ROCKETPORT
-   tristate 'Digiboard Intelligent Async Support' CONFIG_DIGIEPCA
-   if [ "$CONFIG_DIGIEPCA" = "n" ]; then
-      tristate 'Digiboard PC/Xx Support' CONFIG_DIGI
-   fi
    tristate 'Cyclades async mux support' CONFIG_CYCLADES
    if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_CYCLADES" != "n" ]; then
       bool '  Cyclades-Z interrupt mode operation (EXPERIMENTAL)' CONFIG_CYZ_INTR
    fi
-   bool 'Stallion multiport serial support' CONFIG_STALDRV
-   if [ "$CONFIG_STALDRV" = "y" ]; then
-     tristate '  Stallion EasyIO or EC8/32 support' CONFIG_STALLION
-     tristate '  Stallion EC8/64, ONboard, Brumby support' CONFIG_ISTALLION
+   tristate 'Digiboard Intelligent Async Support' CONFIG_DIGIEPCA
+   if [ "$CONFIG_DIGIEPCA" = "n" ]; then
+      tristate 'Digiboard PC/Xx Support' CONFIG_DIGI
+   fi
+   tristate 'Hayes ESP serial port support' CONFIG_ESPSERIAL
+   tristate 'Moxa Intellio support' CONFIG_MOXA_INTELLIO
+   tristate 'Moxa SmartIO support' CONFIG_MOXA_SMARTIO
+   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+	dep_tristate 'Multi-Tech multiport card support' CONFIG_ISI m
    fi
    tristate 'SDL RISCom/8 card support' CONFIG_RISCOM8
-   tristate 'Computone IntelliPort Plus serial support' CONFIG_COMPUTONE
    tristate 'Specialix IO8+ card support' CONFIG_SPECIALIX
    if [ "$CONFIG_SPECIALIX" != "n" ]; then
      bool 'Specialix DTR/RTS pin is RTS' CONFIG_SPECIALIX_RTSCTS
    fi 
    tristate 'Specialix SX (and SI) card support' CONFIG_SX
-   tristate 'Hayes ESP serial port support' CONFIG_ESPSERIAL
-   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-	dep_tristate 'Multi-Tech multiport card support' CONFIG_ISI m
+   bool 'Stallion multiport serial support' CONFIG_STALDRV
+   if [ "$CONFIG_STALDRV" = "y" ]; then
+     tristate '  Stallion EasyIO or EC8/32 support' CONFIG_STALLION
+     tristate '  Stallion EC8/64, ONboard, Brumby support' CONFIG_ISTALLION
    fi
    dep_tristate 'Microgate SyncLink card support' CONFIG_SYNCLINK m
    dep_tristate 'HDLC line discipline support' CONFIG_N_HDLC m
diff -urN linux-2.2.14-pre16/drivers/char/Makefile linux-2.2.14-pre17/drivers/char/Makefile
--- linux-2.2.14-pre16/drivers/char/Makefile	2003-08-15 15:10:01.000000000 -0700
+++ linux-2.2.14-pre17/drivers/char/Makefile	2003-08-15 15:10:02.000000000 -0700
@@ -94,6 +94,22 @@
   endif
 endif
 
+ifeq ($(CONFIG_MOXA_SMARTIO),y)
+L_OBJS += mxser.o
+else
+  ifeq ($(CONFIG_MOXA_SMARTIO),m)
+  M_OBJS += mxser.o
+  endif
+endif
+
+ifeq ($(CONFIG_MOXA_INTELLIO),y)
+L_OBJS += moxa.o
+else
+  ifeq ($(CONFIG_MOXA_INTELLIO),m)
+  M_OBJS += moxa.o
+  endif
+endif
+
 ifeq ($(CONFIG_DIGI),y)
 L_OBJS += pcxx.o
 else
diff -urN linux-2.2.14-pre16/drivers/char/moxa.c linux-2.2.14-pre17/drivers/char/moxa.c
--- linux-2.2.14-pre16/drivers/char/moxa.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.2.14-pre17/drivers/char/moxa.c	2003-08-15 15:10:02.000000000 -0700
@@ -0,0 +1,3319 @@
+/*****************************************************************************/
+/*
+ *           moxa.c  -- MOXA Intellio family multiport serial driver.
+ *
+ *      Copyright (C) 1999-2000  Moxa Technologies (support@moxa.com.tw).
+ *
+ *      This code is loosely based on the Linux serial driver, written by
+ *      Linus Torvalds, Theodore T'so and others.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ *    MOXA Intellio Series Driver
+ *      for             : LINUX
+ *      date            : 1999/1/7
+ *      version         : 5.1
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/version.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/config.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/serial.h>
+#include <linux/tty_driver.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/segment.h>
+#include <asm/bitops.h>
+#include <asm/uaccess.h>
+
+#define		MOXA_VERSION		"5.1k"
+
+#define MOXAMAJOR       172
+#define MOXACUMAJOR     173
+
+#define put_to_user(arg1, arg2) put_user(arg1, (unsigned long *)arg2)
+#define get_from_user(arg1, arg2) get_user(arg1, (unsigned int *)arg2)
+
+#define MAX_BOARDS 		4	/* Don't change this value */
+#define MAX_PORTS_PER_BOARD	32	/* Don't change this value */
+#define MAX_PORTS 		128	/* Don't change this value */
+
+/*
+ *    Define the Moxa PCI vendor and device IDs.
+ */
+#define MOXA_BUS_TYPE_ISA		0
+#define MOXA_BUS_TYPE_PCI		1
+
+#ifndef	PCI_VENDOR_ID_MOXA
+#define	PCI_VENDOR_ID_MOXA	0x1393
+#endif
+#ifndef PCI_DEVICE_ID_CP204J
+#define PCI_DEVICE_ID_CP204J	0x2040
+#endif
+#ifndef PCI_DEVICE_ID_C218
+#define PCI_DEVICE_ID_C218	0x2180
+#endif
+#ifndef PCI_DEVICE_ID_C320
+#define PCI_DEVICE_ID_C320	0x3200
+#endif
+
+enum {
+	MOXA_BOARD_C218_PCI = 1,
+	MOXA_BOARD_C218_ISA,
+	MOXA_BOARD_C320_PCI,
+	MOXA_BOARD_C320_ISA,
+	MOXA_BOARD_CP204J,
+};
+
+static char *moxa_brdname[] =
+{
+	"C218 Turbo PCI series",
+	"C218 Turbo ISA series",
+	"C320 Turbo PCI series",
+	"C320 Turbo ISA series",
+	"CP-204J series",
+};
+
+typedef struct {
+	unsigned short vendor_id;
+	unsigned short device_id;
+	unsigned short board_type;
+} moxa_pciinfo;
+
+static moxa_pciinfo moxa_pcibrds[] =
+{
+	{PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_C218, MOXA_BOARD_C218_PCI},
+	{PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_C320, MOXA_BOARD_C320_PCI},
+	{PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_CP204J, MOXA_BOARD_CP204J},
+};
+
+typedef struct _moxa_isa_board_conf {
+	int boardType;
+	int numPorts;
+	unsigned long baseAddr;
+} moxa_isa_board_conf;
+
+static moxa_isa_board_conf moxa_isa_boards[] =
+{
+/*       {MOXA_BOARD_C218_ISA,8,0xDC000}, */
+};
+
+typedef struct _moxa_pci_devinfo {
+	ushort busNum;
+	ushort devNum;
+} moxa_pci_devinfo;
+
+typedef struct _moxa_board_conf {
+	int boardType;
+	int numPorts;
+	unsigned long baseAddr;
+	int busType;
+	moxa_pci_devinfo pciInfo;
+} moxa_board_conf;
+
+static moxa_board_conf moxa_boards[MAX_BOARDS];
+static unsigned long moxaBaseAddr[MAX_BOARDS];
+
+struct moxa_str {
+	int type;
+	int port;
+	int close_delay;
+	unsigned short closing_wait;
+	int count;
+	int blocked_open;
+	int event;
+	int asyncflags;
+	long session;
+	long pgrp;
+	unsigned long statusflags;
+	struct tty_struct *tty;
+	struct termios normal_termios;
+	struct termios callout_termios;
+	struct wait_queue *open_wait;
+	struct wait_queue *close_wait;
+	struct tq_struct tqueue;
+};
+
+struct mxser_mstatus {
+	tcflag_t cflag;
+	int cts;
+	int dsr;
+	int ri;
+	int dcd;
+};
+
+static struct mxser_mstatus GMStatus[MAX_PORTS];
+
+/* statusflags */
+#define TXSTOPPED	0x1
+#define LOWWAIT 	0x2
+#define EMPTYWAIT	0x4
+#define THROTTLE	0x8
+
+/* event */
+#define MOXA_EVENT_HANGUP	1
+
+#define SERIAL_DO_RESTART
+
+
+#define SERIAL_TYPE_NORMAL	1
+#define SERIAL_TYPE_CALLOUT	2
+
+#define WAKEUP_CHARS		256
+
+#define PORTNO(x)		(MINOR((x)->device) - (x)->driver.minor_start)
+
+static int verbose = 0;
+static int ttymajor = MOXAMAJOR;
+static int calloutmajor = MOXACUMAJOR;
+#ifdef MODULE
+/* Variables for insmod */
+static int baseaddr[] 	= 	{0, 0, 0, 0};
+static int type[]	=	{0, 0, 0, 0};
+static int numports[] 	=	{0, 0, 0, 0};
+
+MODULE_AUTHOR("William Chen");
+MODULE_DESCRIPTION("MOXA Intellio Family Multiport Board Device Driver");
+MODULE_PARM(type, "1-4i");
+MODULE_PARM(baseaddr, "1-4i");
+MODULE_PARM(numports, "1-4i");
+MODULE_PARM(ttymajor, "i");
+MODULE_PARM(calloutmajor, "i");
+MODULE_PARM(verbose, "i");
+
+#endif				//MODULE
+
+static struct tty_driver moxaDriver;
+static struct tty_driver moxaCallout;
+static struct tty_struct *moxaTable[MAX_PORTS + 1];
+static struct termios *moxaTermios[MAX_PORTS + 1];
+static struct termios *moxaTermiosLocked[MAX_PORTS + 1];
+static struct moxa_str moxaChannels[MAX_PORTS];
+static int moxaRefcount;
+unsigned char *moxaXmitBuff;
+static int moxaTimer_on;
+struct timer_list moxaTimer;
+static int moxaEmptyTimer_on[MAX_PORTS];
+struct timer_list moxaEmptyTimer[MAX_PORTS];
+struct semaphore moxaBuffSem = MUTEX;
+
+int moxa_init(void);
+#ifdef MODULE
+int init_module(void);
+void cleanup_module(void);
+#endif
+/*
+ * static functions:
+ */
+static int moxa_get_PCI_conf(struct pci_dev *, int, moxa_board_conf *);
+static void do_moxa_softint(void *);
+static int moxa_open(struct tty_struct *, struct file *);
+static void moxa_close(struct tty_struct *, struct file *);
+static int moxa_write(struct tty_struct *, int, const unsigned char *, int);
+static int moxa_write_room(struct tty_struct *);
+static void moxa_flush_buffer(struct tty_struct *);
+static int moxa_chars_in_buffer(struct tty_struct *);
+static void moxa_flush_chars(struct tty_struct *);
+static void moxa_put_char(struct tty_struct *, unsigned char);
+static int moxa_ioctl(struct tty_struct *, struct file *, unsigned int, unsigned long);
+static void moxa_throttle(struct tty_struct *);
+static void moxa_unthrottle(struct tty_struct *);
+static void moxa_set_termios(struct tty_struct *, struct termios *);
+static void moxa_stop(struct tty_struct *);
+static void moxa_start(struct tty_struct *);
+static void moxa_hangup(struct tty_struct *);
+static void moxa_poll(unsigned long);
+static void set_tty_param(struct tty_struct *);
+static int block_till_ready(struct tty_struct *, struct file *,
+			    struct moxa_str *);
+static void setup_empty_event(struct tty_struct *);
+static void check_xmit_empty(unsigned long);
+static void shut_down(struct moxa_str *);
+static void receive_data(struct moxa_str *);
+/*
+ * moxa board interface functions:
+ */
+static void MoxaDriverInit(void);
+static int MoxaDriverIoctl(unsigned int, unsigned long, int);
+static int MoxaDriverPoll(void);
+static int MoxaPortsOfCard(int);
+static int MoxaPortIsValid(int);
+static void MoxaPortEnable(int);
+static void MoxaPortDisable(int);
+static long MoxaPortGetMaxBaud(int);
+static long MoxaPortSetBaud(int, long);
+static int MoxaPortSetTermio(int, struct termios *);
+static int MoxaPortGetLineOut(int, int *, int *);
+static void MoxaPortLineCtrl(int, int, int);
+static void MoxaPortFlowCtrl(int, int, int, int, int, int);
+static int MoxaPortLineStatus(int);
+static int MoxaPortDCDChange(int);
+static int MoxaPortDCDON(int);
+static void MoxaPortFlushData(int, int);
+static int MoxaPortWriteData(int, unsigned char *, int);
+static int MoxaPortReadData(int, unsigned char *, int);
+static int MoxaPortTxQueue(int);
+static int MoxaPortRxQueue(int);
+static int MoxaPortTxFree(int);
+static void MoxaPortTxDisable(int);
+static void MoxaPortTxEnable(int);
+static int MoxaPortResetBrkCnt(int);
+static void MoxaPortSendBreak(int, int);
+static int moxa_get_serial_info(struct moxa_str *, struct serial_struct *);
+static int moxa_set_serial_info(struct moxa_str *, struct serial_struct *);
+static void MoxaSetFifo(int port, int enable);
+
+#ifdef MODULE
+int init_module(void)
+{
+	int ret;
+
+	if (verbose)
+		printk("Loading module moxa ...\n");
+	ret = moxa_init();
+	if (verbose)
+		printk("Done\n");
+	return (ret);
+}
+
+void cleanup_module(void)
+{
+	int i;
+
+	if (verbose)
+		printk("Unloading module moxa ...\n");
+
+	if (moxaTimer_on)
+		del_timer(&moxaTimer);
+
+	for (i = 0; i < MAX_PORTS; i++)
+		if (moxaEmptyTimer_on[i])
+			del_timer(&moxaEmptyTimer[i]);
+
+	if (tty_unregister_driver(&moxaCallout))
+		printk("Couldn't unregister MOXA Intellio family callout driver\n");
+	if (tty_unregister_driver(&moxaDriver))
+		printk("Couldn't unregister MOXA Intellio family serial driver\n");
+	if (verbose)
+		printk("Done\n");
+
+}
+#endif
+
+int moxa_init(void)
+{
+	int i, n, numBoards;
+	struct moxa_str *ch;
+	int ret1, ret2;
+
+	printk(KERN_INFO "MOXA Intellio family driver version %s\n", MOXA_VERSION);
+
+	memset(&moxaDriver, 0, sizeof(struct tty_driver));
+	memset(&moxaCallout, 0, sizeof(struct tty_driver));
+	moxaDriver.magic = TTY_DRIVER_MAGIC;
+	moxaDriver.name = "ttya";
+	moxaDriver.major = ttymajor;
+	moxaDriver.minor_start = 0;
+	moxaDriver.num = MAX_PORTS + 1;
+	moxaDriver.type = TTY_DRIVER_TYPE_SERIAL;
+	moxaDriver.subtype = SERIAL_TYPE_NORMAL;
+	moxaDriver.init_termios = tty_std_termios;
+	moxaDriver.init_termios.c_iflag = 0;
+	moxaDriver.init_termios.c_oflag = 0;
+	moxaDriver.init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
+	moxaDriver.init_termios.c_lflag = 0;
+	moxaDriver.flags = TTY_DRIVER_REAL_RAW;
+	moxaDriver.refcount = &moxaRefcount;
+	moxaDriver.table = moxaTable;
+	moxaDriver.termios = moxaTermios;
+	moxaDriver.termios_locked = moxaTermiosLocked;
+
+	moxaDriver.open = moxa_open;
+	moxaDriver.close = moxa_close;
+	moxaDriver.write = moxa_write;
+	moxaDriver.write_room = moxa_write_room;
+	moxaDriver.flush_buffer = moxa_flush_buffer;
+	moxaDriver.chars_in_buffer = moxa_chars_in_buffer;
+	moxaDriver.flush_chars = moxa_flush_chars;
+	moxaDriver.put_char = moxa_put_char;
+	moxaDriver.ioctl = moxa_ioctl;
+	moxaDriver.throttle = moxa_throttle;
+	moxaDriver.unthrottle = moxa_unthrottle;
+	moxaDriver.set_termios = moxa_set_termios;
+	moxaDriver.stop = moxa_stop;
+	moxaDriver.start = moxa_start;
+	moxaDriver.hangup = moxa_hangup;
+
+	moxaCallout = moxaDriver;
+	moxaCallout.name = "ttyA";
+	moxaCallout.major = calloutmajor;
+	moxaCallout.subtype = SERIAL_TYPE_CALLOUT;
+
+	moxaXmitBuff = 0;
+
+	for (i = 0, ch = moxaChannels; i < MAX_PORTS; i++, ch++) {
+		ch->type = PORT_16550A;
+		ch->port = i;
+		ch->tqueue.routine = do_moxa_softint;
+		ch->tqueue.data = ch;
+		ch->tty = 0;
+		ch->close_delay = 5 * HZ / 10;
+		ch->closing_wait = 30 * HZ;
+		ch->count = 0;
+		ch->blocked_open = 0;
+		ch->callout_termios = moxaCallout.init_termios;
+		ch->normal_termios = moxaDriver.init_termios;
+		ch->open_wait = 0;
+		ch->close_wait = 0;
+	}
+
+	for (i = 0; i < MAX_BOARDS; i++) {
+		moxa_boards[i].boardType = 0;
+		moxa_boards[i].numPorts = 0;
+		moxa_boards[i].baseAddr = 0;
+		moxa_boards[i].busType = 0;
+		moxa_boards[i].pciInfo.busNum = 0;
+		moxa_boards[i].pciInfo.devNum = 0;
+	}
+	MoxaDriverInit();
+	printk("Tty devices major number = %d, callout devices major number = %d\n", ttymajor, calloutmajor);
+
+	ret1 = 0;
+	ret2 = 0;
+	if ((ret1 = tty_register_driver(&moxaDriver))) {
+		printk(KERN_ERR "Couldn't install MOXA Smartio family driver !\n");
+	} else if ((ret2 = tty_register_driver(&moxaCallout))) {
+		tty_unregister_driver(&moxaDriver);
+		printk(KERN_ERR "Couldn't install MOXA Smartio family callout driver !\n");
+	}
+	if (ret1 || ret2) {
+		return -1;
+	}
+	for (i = 0; i < MAX_PORTS; i++) {
+		init_timer(&moxaEmptyTimer[i]);
+		moxaEmptyTimer[i].function = check_xmit_empty;
+		moxaEmptyTimer[i].data = (unsigned long) & moxaChannels[i];
+		moxaEmptyTimer_on[i] = 0;
+	}
+
+	init_timer(&moxaTimer);
+	moxaTimer.function = moxa_poll;
+	moxaTimer.expires = jiffies + (HZ / 50);
+	moxaTimer_on = 1;
+	add_timer(&moxaTimer);
+
+	/* Find the boards defined in source code */
+	numBoards = 0;
+	for (i = 0; i < MAX_BOARDS; i++) {
+		if ((moxa_isa_boards[i].boardType == MOXA_BOARD_C218_ISA) ||
+		 (moxa_isa_boards[i].boardType == MOXA_BOARD_C320_ISA)) {
+			moxa_boards[numBoards].boardType = moxa_isa_boards[i].boardType;
+			if (moxa_isa_boards[i].boardType == MOXA_BOARD_C218_ISA)
+				moxa_boards[numBoards].numPorts = 8;
+			else
+				moxa_boards[numBoards].numPorts = moxa_isa_boards[i].numPorts;
+			moxa_boards[numBoards].busType = MOXA_BUS_TYPE_ISA;
+			moxa_boards[numBoards].baseAddr = moxa_isa_boards[i].baseAddr;
+			if (verbose)
+				printk("Board %2d: %s board(baseAddr=%lx)\n",
+				       numBoards + 1,
+				       moxa_brdname[moxa_boards[numBoards].boardType - 1],
+				       moxa_boards[numBoards].baseAddr);
+			numBoards++;
+		}
+	}
+	/* Find the boards defined form module args. */
+#ifdef MODULE
+	for (i = 0; i < MAX_BOARDS; i++) {
+		if ((type[i] == MOXA_BOARD_C218_ISA) ||
+		    (type[i] == MOXA_BOARD_C320_ISA)) {
+			if (verbose)
+				printk("Board %2d: %s board(baseAddr=%lx)\n",
+				       numBoards + 1,
+				       moxa_brdname[type[i] - 1],
+				       (unsigned long) baseaddr[i]);
+			if (numBoards >= MAX_BOARDS) {
+				if (verbose)
+					printk("More than %d MOXA Intellio family boards found. Board is ignored.", MAX_BOARDS);
+				continue;
+			}
+			moxa_boards[numBoards].boardType = type[i];
+			if (moxa_isa_boards[i].boardType == MOXA_BOARD_C218_ISA)
+				moxa_boards[numBoards].numPorts = 8;
+			else
+				moxa_boards[numBoards].numPorts = numports[i];
+			moxa_boards[numBoards].busType = MOXA_BUS_TYPE_ISA;
+			moxa_boards[numBoards].baseAddr = baseaddr[i];
+			numBoards++;
+		}
+	}
+#endif
+	/* Find PCI boards here */
+#ifdef CONFIG_PCI
+	if (pci_present()) {
+		struct pci_dev *p = NULL;
+		n = sizeof(moxa_pcibrds) / sizeof(moxa_pciinfo);
+		i = 0;
+		while (i < n) {
+			while((p = pci_find_device(moxa_pcibrds[i].vendor_id, moxa_pcibrds[i].device_id, p))!=NULL)
+			{
+				if (numBoards >= MAX_BOARDS) {
+					if (verbose)
+						printk("More than %d MOXA Intellio family boards found. Board is ignored.", MAX_BOARDS);
+				} else {
+					moxa_get_PCI_conf(p, moxa_pcibrds[i].board_type,
+						&moxa_boards[numBoards]);
+					numBoards++;
+				}
+			}
+			i++;
+		}
+	}
+#endif
+	for (i = 0; i < numBoards; i++) {
+		moxaBaseAddr[i] = (unsigned long) ioremap((unsigned long) moxa_boards[i].baseAddr, 0x4000);
+	}
+
+	return (0);
+}
+
+static int moxa_get_PCI_conf(struct pci_dev *p, int board_type, moxa_board_conf * board)
+{
+	unsigned int val;
+
+	board->baseAddr = p->base_address[2] & PCI_BASE_ADDRESS_MEM_MASK;
+	board->boardType = board_type;
+	switch (board_type) {
+	case MOXA_BOARD_C218_ISA:
+	case MOXA_BOARD_C218_PCI:
+		board->numPorts = 8;
+		break;
+
+	case MOXA_BOARD_CP204J:
+		board->numPorts = 4;
+		break;
+	default:
+		board->numPorts = 0;
+		break;
+	}
+	board->busType = MOXA_BUS_TYPE_PCI;
+	board->pciInfo.busNum = p->bus->number;
+	board->pciInfo.devNum = p->devfn >> 3;
+
+	return (0);
+}
+
+static void do_moxa_softint(void *private_)
+{
+	struct moxa_str *ch = (struct moxa_str *) private_;
+	struct tty_struct *tty;
+
+	if (!ch || !(tty = ch->tty))
+		return;
+	if (test_and_clear_bit(MOXA_EVENT_HANGUP, &ch->event)) {
+		tty_hangup(tty);
+		wake_up_interruptible(&ch->open_wait);
+		ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE);
+	}
+}
+
+static int moxa_open(struct tty_struct *tty, struct file *filp)
+{
+	struct moxa_str *ch;
+	int port;
+	int retval;
+	unsigned long page;
+
+	port = PORTNO(tty);
+	if (port == MAX_PORTS) {
+		MOD_INC_USE_COUNT;
+		return (0);
+	}
+	if (!MoxaPortIsValid(port)) {
+		tty->driver_data = NULL;
+		return (-ENODEV);
+	}
+	down(&moxaBuffSem);
+	if (!moxaXmitBuff) {
+		page = get_free_page(GFP_KERNEL);
+		if (!page) {
+			up(&moxaBuffSem);
+			return (-ENOMEM);
+		}
+		if (moxaXmitBuff)
+			free_page(page);
+		else
+			moxaXmitBuff = (unsigned char *) page;
+	}
+	up(&moxaBuffSem);
+
+	MOD_INC_USE_COUNT;
+	ch = &moxaChannels[port];
+	ch->count++;
+	tty->driver_data = ch;
+	ch->tty = tty;
+	if (ch->count == 1 && (ch->asyncflags & ASYNC_SPLIT_TERMIOS)) {
+		if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+			*tty->termios = ch->normal_termios;
+		else
+			*tty->termios = ch->callout_termios;
+	}
+	ch->session = current->session;
+	ch->pgrp = current->pgrp;
+	if (!(ch->asyncflags & ASYNC_INITIALIZED)) {
+		ch->statusflags = 0;
+		set_tty_param(tty);
+		MoxaPortLineCtrl(ch->port, 1, 1);
+		MoxaPortEnable(ch->port);
+		ch->asyncflags |= ASYNC_INITIALIZED;
+	}
+	retval = block_till_ready(tty, filp, ch);
+
+	moxa_unthrottle(tty);
+
+	if (ch->type == PORT_16550A) {
+		MoxaSetFifo(ch->port, 1);
+	} else {
+		MoxaSetFifo(ch->port, 0);
+	}
+
+	return (retval);
+}
+
+static void moxa_close(struct tty_struct *tty, struct file *filp)
+{
+	struct moxa_str *ch;
+	int port;
+
+	port = PORTNO(tty);
+	if (port == MAX_PORTS) {
+		MOD_DEC_USE_COUNT;
+		return;
+	}
+	if (!MoxaPortIsValid(port)) {
+#ifdef SERIAL_DEBUG_CLOSE
+		printk("Invalid portno in moxa_close\n");
+#endif
+		tty->driver_data = NULL;
+		return;
+	}
+	if (tty->driver_data == NULL) {
+		return;
+	}
+	if (tty_hung_up_p(filp)) {
+		MOD_DEC_USE_COUNT;
+		return;
+	}
+	ch = (struct moxa_str *) tty->driver_data;
+
+	if ((tty->count == 1) && (ch->count != 1)) {
+		printk("moxa_close: bad serial port count; tty->count is 1, "
+		       "ch->count is %d\n", ch->count);
+		ch->count = 1;
+	}
+	if (--ch->count < 0) {
+		printk("moxa_close: bad serial port count, minor=%d\n",
+		       MINOR(tty->device));
+		ch->count = 0;
+	}
+	if (ch->count) {
+		MOD_DEC_USE_COUNT;
+		return;
+	}
+	ch->asyncflags |= ASYNC_CLOSING;
+
+	/*
+	 * Save the termios structure, since this port may have
+	 * separate termios for callout and dialin.
+	 */
+	if (ch->asyncflags & ASYNC_NORMAL_ACTIVE)
+		ch->normal_termios = *tty->termios;
+	if (ch->asyncflags & ASYNC_CALLOUT_ACTIVE)
+		ch->callout_termios = *tty->termios;
+	if (ch->asyncflags & ASYNC_INITIALIZED) {
+		setup_empty_event(tty);
+		tty_wait_until_sent(tty, 30 * HZ);	/* 30 seconds timeout */
+		moxaEmptyTimer_on[ch->port] = 0;
+		del_timer(&moxaEmptyTimer[ch->port]);
+	}
+	shut_down(ch);
+	MoxaPortFlushData(port, 2);
+
+	if (tty->driver.flush_buffer)
+		tty->driver.flush_buffer(tty);
+	if (tty->ldisc.flush_buffer)
+		tty->ldisc.flush_buffer(tty);
+	tty->closing = 0;
+	ch->event = 0;
+	ch->tty = 0;
+	if (ch->blocked_open) {
+		if (ch->close_delay) {
+			current->state = TASK_INTERRUPTIBLE;
+			schedule_timeout(ch->close_delay);
+		}
+		wake_up_interruptible(&ch->open_wait);
+	}
+	ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE |
+			    ASYNC_CLOSING);
+	wake_up_interruptible(&ch->close_wait);
+	MOD_DEC_USE_COUNT;
+}
+
+static int moxa_write(struct tty_struct *tty, int from_user,
+		      const unsigned char *buf, int count)
+{
+	struct moxa_str *ch;
+	int len, port;
+	unsigned long flags;
+	unsigned char *temp;
+
+	ch = (struct moxa_str *) tty->driver_data;
+	if (ch == NULL)
+		return (0);
+	port = ch->port;
+	save_flags(flags);
+	cli();
+	if (from_user) {
+		copy_from_user(moxaXmitBuff, buf, count);
+		temp = moxaXmitBuff;
+	} else
+		temp = (unsigned char *) buf;
+	len = MoxaPortWriteData(port, temp, count);
+	restore_flags(flags);
+	/*********************************************
+	if ( !(ch->statusflags & LOWWAIT) &&
+	     ((len != count) || (MoxaPortTxFree(port) <= 100)) )
+	************************************************/
+	ch->statusflags |= LOWWAIT;
+	return (len);
+}
+
+static int moxa_write_room(struct tty_struct *tty)
+{
+	struct moxa_str *ch;
+
+	if (tty->stopped)
+		return (0);
+	ch = (struct moxa_str *) tty->driver_data;
+	if (ch == NULL)
+		return (0);
+	return (MoxaPortTxFree(ch->port));
+}
+
+static void moxa_flush_buffer(struct tty_struct *tty)
+{
+	struct moxa_str *ch = (struct moxa_str *) tty->driver_data;
+
+	if (ch == NULL)
+		return;
+	MoxaPortFlushData(ch->port, 1);
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+	    tty->ldisc.write_wakeup)
+		(tty->ldisc.write_wakeup) (tty);
+	wake_up_interruptible(&tty->write_wait);
+}
+
+static int moxa_chars_in_buffer(struct tty_struct *tty)
+{
+	int chars;
+	struct moxa_str *ch = (struct moxa_str *) tty->driver_data;
+
+	/*
+	 * Sigh...I have to check if driver_data is NULL here, because
+	 * if an open() fails, the TTY subsystem eventually calls
+	 * tty_wait_until_sent(), which calls the driver's chars_in_buffer()
+	 * routine.  And since the open() failed, we return 0 here.  TDJ
+	 */
+	if (ch == NULL)
+		return (0);
+	chars = MoxaPortTxQueue(ch->port);
+	if (chars) {
+		/*
+		 * Make it possible to wakeup anything waiting for output
+		 * in tty_ioctl.c, etc.
+		 */
+		if (!(ch->statusflags & EMPTYWAIT))
+			setup_empty_event(tty);
+	}
+	return (chars);
+}
+
+static void moxa_flush_chars(struct tty_struct *tty)
+{
+	/*
+	 * Don't think I need this, because this is called to empty the TX
+	 * buffer for the 16450, 16550, etc.
+	 */
+}
+
+static void moxa_put_char(struct tty_struct *tty, unsigned char c)
+{
+	struct moxa_str *ch;
+	int port;
+	unsigned long flags;
+
+	ch = (struct moxa_str *) tty->driver_data;
+	if (ch == NULL)
+		return;
+	port = ch->port;
+	save_flags(flags);
+	cli();
+	moxaXmitBuff[0] = c;
+	MoxaPortWriteData(port, moxaXmitBuff, 1);
+	restore_flags(flags);
+	/************************************************
+	if ( !(ch->statusflags & LOWWAIT) && (MoxaPortTxFree(port) <= 100) )
+	*************************************************/
+	ch->statusflags |= LOWWAIT;
+}
+
+static int moxa_ioctl(struct tty_struct *tty, struct file *file,
+		      unsigned int cmd, unsigned long arg)
+{
+	struct moxa_str *ch = (struct moxa_str *) tty->driver_data;
+	register int port;
+	int retval, dtr, rts;
+	unsigned long flag;
+
+	port = PORTNO(tty);
+	if ((port != MAX_PORTS) && (!ch))
+		return (-EINVAL);
+
+	switch (cmd) {
+	case TCSBRK:		/* SVID version: non-zero arg --> no break */
+		retval = tty_check_change(tty);
+		if (retval)
+			return (retval);
+		setup_empty_event(tty);
+		tty_wait_until_sent(tty, 0);
+		if (!arg)
+			MoxaPortSendBreak(ch->port, 0);
+		return (0);
+	case TCSBRKP:		/* support for POSIX tcsendbreak() */
+		retval = tty_check_change(tty);
+		if (retval)
+			return (retval);
+		setup_empty_event(tty);
+		tty_wait_until_sent(tty, 0);
+		MoxaPortSendBreak(ch->port, arg);
+		return (0);
+	case TIOCGSOFTCAR:
+		return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg);
+	case TIOCSSOFTCAR:
+		if(get_user(retval, (unsigned long *) arg))
+			return -EFAULT;
+		arg = retval;
+		tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) |
+					 (arg ? CLOCAL : 0));
+		if (C_CLOCAL(tty))
+			ch->asyncflags &= ~ASYNC_CHECK_CD;
+		else
+			ch->asyncflags |= ASYNC_CHECK_CD;
+		return (0);
+	case TIOCMGET:
+		flag = 0;
+		MoxaPortGetLineOut(ch->port, &dtr, &rts);
+		if (dtr)
+			flag |= TIOCM_DTR;
+		if (rts)
+			flag |= TIOCM_RTS;
+		dtr = MoxaPortLineStatus(ch->port);
+		if (dtr & 1)
+			flag |= TIOCM_CTS;
+		if (dtr & 2)
+			flag |= TIOCM_DSR;
+		if (dtr & 4)
+			flag |= TIOCM_CD;
+		return put_user(flag, (unsigned int *) arg);
+	case TIOCMBIS:
+		if(get_user(retval, (unsigned int *) arg))
+			return -EFAULT;
+		MoxaPortGetLineOut(ch->port, &dtr, &rts);
+		if (retval & TIOCM_RTS)
+			rts = 1;
+		if (retval & TIOCM_DTR)
+			dtr = 1;
+		MoxaPortLineCtrl(ch->port, dtr, rts);
+		return (0);
+	case TIOCMBIC:
+		if(get_user(retval, (unsigned int *) arg))
+			return -EFAULT;
+		MoxaPortGetLineOut(ch->port, &dtr, &rts);
+		if (retval & TIOCM_RTS)
+			rts = 0;
+		if (retval & TIOCM_DTR)
+			dtr = 0;
+		MoxaPortLineCtrl(ch->port, dtr, rts);
+		return (0);
+	case TIOCMSET:
+		if(get_user(retval, (unsigned long *) arg))
+			return -EFAULT;
+		dtr = rts = 0;
+		if (retval & TIOCM_RTS)
+			rts = 1;
+		if (retval & TIOCM_DTR)
+			dtr = 1;
+		MoxaPortLineCtrl(ch->port, dtr, rts);
+		return (0);
+	case TIOCGSERIAL:
+		return (moxa_get_serial_info(ch, (struct serial_struct *) arg));
+
+	case TIOCSSERIAL:
+		return (moxa_set_serial_info(ch, (struct serial_struct *) arg));
+	default:
+		retval = MoxaDriverIoctl(cmd, arg, port);
+	}
+	return (retval);
+}
+
+static void moxa_throttle(struct tty_struct *tty)
+{
+	struct moxa_str *ch = (struct moxa_str *) tty->driver_data;
+
+	ch->statusflags |= THROTTLE;
+}
+
+static void moxa_unthrottle(struct tty_struct *tty)
+{
+	struct moxa_str *ch = (struct moxa_str *) tty->driver_data;
+
+	ch->statusflags &= ~THROTTLE;
+}
+
+static void moxa_set_termios(struct tty_struct *tty,
+			     struct termios *old_termios)
+{
+	struct moxa_str *ch = (struct moxa_str *) tty->driver_data;
+
+	if (ch == NULL)
+		return;
+	set_tty_param(tty);
+	if (!(old_termios->c_cflag & CLOCAL) &&
+	    (tty->termios->c_cflag & CLOCAL))
+		wake_up_interruptible(&ch->open_wait);
+}
+
+static void moxa_stop(struct tty_struct *tty)
+{
+	struct moxa_str *ch = (struct moxa_str *) tty->driver_data;
+
+	if (ch == NULL)
+		return;
+	MoxaPortTxDisable(ch->port);
+	ch->statusflags |= TXSTOPPED;
+}
+
+
+static void moxa_start(struct tty_struct *tty)
+{
+	struct moxa_str *ch = (struct moxa_str *) tty->driver_data;
+
+	if (ch == NULL)
+		return;
+
+	if (!(ch->statusflags & TXSTOPPED))
+		return;
+
+	MoxaPortTxEnable(ch->port);
+	ch->statusflags &= ~TXSTOPPED;
+}
+
+static void moxa_hangup(struct tty_struct *tty)
+{
+	struct moxa_str *ch = (struct moxa_str *) tty->driver_data;
+
+	moxa_flush_buffer(tty);
+	shut_down(ch);
+	ch->event = 0;
+	ch->count = 0;
+	ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE);
+	ch->tty = 0;
+	wake_up_interruptible(&ch->open_wait);
+}
+
+static void moxa_poll(unsigned long ignored)
+{
+	register int card;
+	struct moxa_str *ch;
+	struct tty_struct *tp;
+	int i, ports;
+
+	moxaTimer_on = 0;
+	del_timer(&moxaTimer);
+
+	if (MoxaDriverPoll() < 0) {
+		moxaTimer.function = moxa_poll;
+		moxaTimer.expires = jiffies + (HZ / 50);
+		moxaTimer_on = 1;
+		add_timer(&moxaTimer);
+		return;
+	}
+	for (card = 0; card < MAX_BOARDS; card++) {
+		if ((ports = MoxaPortsOfCard(card)) <= 0)
+			continue;
+		ch = &moxaChannels[card * MAX_PORTS_PER_BOARD];
+		for (i = 0; i < ports; i++, ch++) {
+			if ((ch->asyncflags & ASYNC_INITIALIZED) == 0)
+				continue;
+			if (!(ch->statusflags & THROTTLE) &&
+			    (MoxaPortRxQueue(ch->port) > 0))
+				receive_data(ch);
+			if ((tp = ch->tty) == 0)
+				continue;
+			if (ch->statusflags & LOWWAIT) {
+				if (MoxaPortTxQueue(ch->port) <= WAKEUP_CHARS) {
+					if (!tp->stopped) {
+						ch->statusflags &= ~LOWWAIT;
+						if ((tp->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+						  tp->ldisc.write_wakeup)
+							(tp->ldisc.write_wakeup) (tp);
+						wake_up_interruptible(&tp->write_wait);
+					}
+				}
+			}
+			if (!I_IGNBRK(tp) && (MoxaPortResetBrkCnt(ch->port) > 0)) {
+				tty_insert_flip_char(tp, 0, TTY_BREAK);
+				tty_schedule_flip(tp);
+			}
+			if (MoxaPortDCDChange(ch->port)) {
+				if (ch->asyncflags & ASYNC_CHECK_CD) {
+					if (MoxaPortDCDON(ch->port))
+						wake_up_interruptible(&ch->open_wait);
+					else {
+						set_bit(MOXA_EVENT_HANGUP, &ch->event);
+						queue_task(&ch->tqueue, &tq_scheduler);
+					}
+				}
+			}
+		}
+	}
+
+	moxaTimer.function = moxa_poll;
+	moxaTimer.expires = jiffies + (HZ / 50);
+	moxaTimer_on = 1;
+	add_timer(&moxaTimer);
+}
+
+/******************************************************************************/
+
+static void set_tty_param(struct tty_struct *tty)
+{
+	register struct termios *ts;
+	struct moxa_str *ch;
+	int rts, cts, txflow, rxflow, xany;
+
+	ch = (struct moxa_str *) tty->driver_data;
+	ts = tty->termios;
+	if (ts->c_cflag & CLOCAL)
+		ch->asyncflags &= ~ASYNC_CHECK_CD;
+	else
+		ch->asyncflags |= ASYNC_CHECK_CD;
+	rts = cts = txflow = rxflow = xany = 0;
+	if (ts->c_cflag & CRTSCTS)
+		rts = cts = 1;
+	if (ts->c_iflag & IXON)
+		txflow = 1;
+	if (ts->c_iflag & IXOFF)
+		rxflow = 1;
+	if (ts->c_iflag & IXANY)
+		xany = 1;
+	MoxaPortFlowCtrl(ch->port, rts, cts, txflow, rxflow, xany);
+	MoxaPortSetTermio(ch->port, ts);
+}
+
+static int block_till_ready(struct tty_struct *tty, struct file *filp,
+			    struct moxa_str *ch)
+{
+	struct wait_queue wait = {current, NULL};
+	unsigned long flags;
+	int retval;
+	int do_clocal = C_CLOCAL(tty);
+
+	/*
+	 * 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) || (ch->asyncflags & ASYNC_CLOSING)) {
+		if (ch->asyncflags & ASYNC_CLOSING)
+			interruptible_sleep_on(&ch->close_wait);
+#ifdef SERIAL_DO_RESTART
+		if (ch->asyncflags & ASYNC_HUP_NOTIFY)
+			return (-EAGAIN);
+		else
+			return (-ERESTARTSYS);
+#else
+		return (-EAGAIN);
+#endif
+	}
+	/*
+	 * If this is a callout device, then just make sure the normal
+	 * device isn't being used.
+	 */
+	if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
+		if (ch->asyncflags & ASYNC_NORMAL_ACTIVE)
+			return (-EBUSY);
+		if ((ch->asyncflags & ASYNC_CALLOUT_ACTIVE) &&
+		    (ch->asyncflags & ASYNC_SESSION_LOCKOUT) &&
+		    (ch->session != current->session))
+			return (-EBUSY);
+		if ((ch->asyncflags & ASYNC_CALLOUT_ACTIVE) &&
+		    (ch->asyncflags & ASYNC_PGRP_LOCKOUT) &&
+		    (ch->pgrp != current->pgrp))
+			return (-EBUSY);
+		ch->asyncflags |= ASYNC_CALLOUT_ACTIVE;
+		return (0);
+	}
+	/*
+	 * If non-blocking mode is set, then make the check up front
+	 * and then exit.
+	 */
+	if (filp->f_flags & O_NONBLOCK) {
+		if (ch->asyncflags & ASYNC_CALLOUT_ACTIVE)
+			return (-EBUSY);
+		ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
+		return (0);
+	}
+	/*
+	 * Block waiting for the carrier detect and the line to become free
+	 */
+	retval = 0;
+	add_wait_queue(&ch->open_wait, &wait);
+#ifdef SERIAL_DEBUG_OPEN
+	printk("block_til_ready before block: ttys%d, count = %d\n",
+	       ch->line, ch->count);
+#endif
+	save_flags(flags);
+	cli();
+	if (!tty_hung_up_p(filp))
+		ch->count--;
+	restore_flags(flags);
+	ch->blocked_open++;
+	while (1) {
+		current->state = TASK_INTERRUPTIBLE;
+		if (tty_hung_up_p(filp) ||
+		    !(ch->asyncflags & ASYNC_INITIALIZED)) {
+#ifdef SERIAL_DO_RESTART
+			if (ch->asyncflags & ASYNC_HUP_NOTIFY)
+				retval = -EAGAIN;
+			else
+				retval = -ERESTARTSYS;
+#else
+			retval = -EAGAIN;
+#endif
+			break;
+		}
+		if (!(ch->asyncflags & ASYNC_CALLOUT_ACTIVE) &&
+		    !(ch->asyncflags & ASYNC_CLOSING) && (do_clocal ||
+						MoxaPortDCDON(ch->port)))
+			break;
+
+		if (signal_pending(current)) {
+			retval = -ERESTARTSYS;
+			break;
+		}
+		schedule();
+	}
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&ch->open_wait, &wait);
+	if (!tty_hung_up_p(filp))
+		ch->count++;
+	ch->blocked_open--;
+#ifdef SERIAL_DEBUG_OPEN
+	printk("block_til_ready after blocking: ttys%d, count = %d\n",
+	       ch->line, ch->count);
+#endif
+	if (retval)
+		return (retval);
+	ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
+	return (0);
+}
+
+static void setup_empty_event(struct tty_struct *tty)
+{
+	struct moxa_str *ch = tty->driver_data;
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	ch->statusflags |= EMPTYWAIT;
+	moxaEmptyTimer_on[ch->port] = 0;
+	del_timer(&moxaEmptyTimer[ch->port]);
+	moxaEmptyTimer[ch->port].expires = jiffies + HZ;
+	moxaEmptyTimer_on[ch->port] = 1;
+	add_timer(&moxaEmptyTimer[ch->port]);
+	restore_flags(flags);
+}
+
+static void check_xmit_empty(unsigned long data)
+{
+	struct moxa_str *ch;
+
+	ch = (struct moxa_str *) data;
+	moxaEmptyTimer_on[ch->port] = 0;
+	del_timer(&moxaEmptyTimer[ch->port]);
+	if (ch->tty && (ch->statusflags & EMPTYWAIT)) {
+		if (MoxaPortTxQueue(ch->port) == 0) {
+			ch->statusflags &= ~EMPTYWAIT;
+			if ((ch->tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+			    ch->tty->ldisc.write_wakeup)
+				(ch->tty->ldisc.write_wakeup) (ch->tty);
+			wake_up_interruptible(&ch->tty->write_wait);
+			return;
+		}
+		moxaEmptyTimer[ch->port].expires = jiffies + HZ;
+		moxaEmptyTimer_on[ch->port] = 1;
+		add_timer(&moxaEmptyTimer[ch->port]);
+	} else
+		ch->statusflags &= ~EMPTYWAIT;
+}
+
+static void shut_down(struct moxa_str *ch)
+{
+	struct tty_struct *tp;
+
+	if (!(ch->asyncflags & ASYNC_INITIALIZED))
+		return;
+
+	tp = ch->tty;
+
+	MoxaPortDisable(ch->port);
+
+	/*
+	 * If we're a modem control device and HUPCL is on, drop RTS & DTR.
+	 */
+	if (tp->termios->c_cflag & HUPCL)
+		MoxaPortLineCtrl(ch->port, 0, 0);
+
+	ch->asyncflags &= ~ASYNC_INITIALIZED;
+}
+
+static void receive_data(struct moxa_str *ch)
+{
+	struct tty_struct *tp;
+	struct termios *ts;
+	int i, count, rc, space;
+	unsigned char *charptr, *flagptr;
+	unsigned long flags;
+
+	ts = 0;
+	tp = ch->tty;
+	if (tp)
+		ts = tp->termios;
+	/**************************************************
+	if ( !tp || !ts || !(ts->c_cflag & CREAD) ) {
+	*****************************************************/
+	if (!tp || !ts) {
+		MoxaPortFlushData(ch->port, 0);
+		return;
+	}
+	space = TTY_FLIPBUF_SIZE - tp->flip.count;
+	if (space <= 0)
+		return;
+	charptr = tp->flip.char_buf_ptr;
+	flagptr = tp->flip.flag_buf_ptr;
+	rc = tp->flip.count;
+	save_flags(flags);
+	cli();
+	count = MoxaPortReadData(ch->port, charptr, space);
+	restore_flags(flags);
+	for (i = 0; i < count; i++)
+		*flagptr++ = 0;
+	charptr += count;
+	rc += count;
+	tp->flip.count = rc;
+	tp->flip.char_buf_ptr = charptr;
+	tp->flip.flag_buf_ptr = flagptr;
+	tty_schedule_flip(ch->tty);
+}
+
+#define Magic_code	0x404
+
+/*
+ *    System Configuration
+ */
+/*
+ *    for C218 BIOS initialization
+ */
+#define C218_ConfBase	0x800
+#define C218_status	(C218_ConfBase + 0)	/* BIOS running status    */
+#define C218_diag	(C218_ConfBase + 2)	/* diagnostic status      */
+#define C218_key	(C218_ConfBase + 4)	/* WORD (0x218 for C218) */
+#define C218DLoad_len	(C218_ConfBase + 6)	/* WORD           */
+#define C218check_sum	(C218_ConfBase + 8)	/* BYTE           */
+#define C218chksum_ok	(C218_ConfBase + 0x0a)	/* BYTE (1:ok)            */
+#define C218_TestRx	(C218_ConfBase + 0x10)	/* 8 bytes for 8 ports    */
+#define C218_TestTx	(C218_ConfBase + 0x18)	/* 8 bytes for 8 ports    */
+#define C218_RXerr	(C218_ConfBase + 0x20)	/* 8 bytes for 8 ports    */
+#define C218_ErrFlag	(C218_ConfBase + 0x28)	/* 8 bytes for 8 ports    */
+
+#define C218_LoadBuf	0x0F00
+#define C218_KeyCode	0x218
+#define CP204J_KeyCode	0x204
+
+/*
+ *    for C320 BIOS initialization
+ */
+#define C320_ConfBase	0x800
+#define C320_LoadBuf	0x0f00
+#define STS_init	0x05	/* for C320_status        */
+
+#define C320_status	C320_ConfBase + 0	/* BIOS running status    */
+#define C320_diag	C320_ConfBase + 2	/* diagnostic status      */
+#define C320_key	C320_ConfBase + 4	/* WORD (0320H for C320) */
+#define C320DLoad_len	C320_ConfBase + 6	/* WORD           */
+#define C320check_sum	C320_ConfBase + 8	/* WORD           */
+#define C320chksum_ok	C320_ConfBase + 0x0a	/* WORD (1:ok)            */
+#define C320bapi_len	C320_ConfBase + 0x0c	/* WORD           */
+#define C320UART_no	C320_ConfBase + 0x0e	/* WORD           */
+
+#define C320_KeyCode	0x320
+
+#define FixPage_addr	0x0000	/* starting addr of static page  */
+#define DynPage_addr	0x2000	/* starting addr of dynamic page */
+#define C218_start	0x3000	/* starting addr of C218 BIOS prg */
+#define Control_reg	0x1ff0	/* select page and reset control */
+#define HW_reset	0x80
+
+/*
+ *    Function Codes
+ */
+#define FC_CardReset	0x80
+#define FC_ChannelReset 1	/* C320 firmware not supported */
+#define FC_EnableCH	2
+#define FC_DisableCH	3
+#define FC_SetParam	4
+#define FC_SetMode	5
+#define FC_SetRate	6
+#define FC_LineControl	7
+#define FC_LineStatus	8
+#define FC_XmitControl	9
+#define FC_FlushQueue	10
+#define FC_SendBreak	11
+#define FC_StopBreak	12
+#define FC_LoopbackON	13
+#define FC_LoopbackOFF	14
+#define FC_ClrIrqTable	15
+#define FC_SendXon	16
+#define FC_SetTermIrq	17	/* C320 firmware not supported */
+#define FC_SetCntIrq	18	/* C320 firmware not supported */
+#define FC_SetBreakIrq	19
+#define FC_SetLineIrq	20
+#define FC_SetFlowCtl	21
+#define FC_GenIrq	22
+#define FC_InCD180	23
+#define FC_OutCD180	24
+#define FC_InUARTreg	23
+#define FC_OutUARTreg	24
+#define FC_SetXonXoff	25
+#define FC_OutCD180CCR	26
+#define FC_ExtIQueue	27
+#define FC_ExtOQueue	28
+#define FC_ClrLineIrq	29
+#define FC_HWFlowCtl	30
+#define FC_GetClockRate 35
+#define FC_SetBaud	36
+#define FC_SetDataMode  41
+#define FC_GetCCSR      43
+#define FC_GetDataError 45
+#define FC_RxControl	50
+#define FC_ImmSend	51
+#define FC_SetXonState	52
+#define FC_SetXoffState	53
+#define FC_SetRxFIFOTrig 54
+#define FC_SetTxFIFOCnt 55
+#define FC_UnixRate	56
+#define FC_UnixResetTimer 57
+
+#define	RxFIFOTrig1	0
+#define	RxFIFOTrig4	1
+#define	RxFIFOTrig8	2
+#define	RxFIFOTrig14	3
+
+/*
+ *    Dual-Ported RAM
+ */
+#define DRAM_global	0
+#define INT_data	(DRAM_global + 0)
+#define Config_base	(DRAM_global + 0x108)
+
+#define IRQindex	(INT_data + 0)
+#define IRQpending	(INT_data + 4)
+#define IRQtable	(INT_data + 8)
+
+/*
+ *    Interrupt Status
+ */
+#define IntrRx		0x01	/* receiver data O.K.             */
+#define IntrTx		0x02	/* transmit buffer empty  */
+#define IntrFunc	0x04	/* function complete              */
+#define IntrBreak	0x08	/* received break         */
+#define IntrLine	0x10	/* line status change
+				   for transmitter                */
+#define IntrIntr	0x20	/* received INTR code             */
+#define IntrQuit	0x40	/* received QUIT code             */
+#define IntrEOF 	0x80	/* received EOF code              */
+
+#define IntrRxTrigger 	0x100	/* rx data count reach tigger value */
+#define IntrTxTrigger 	0x200	/* tx data count below trigger value */
+
+#define Magic_no	(Config_base + 0)
+#define Card_model_no	(Config_base + 2)
+#define Total_ports	(Config_base + 4)
+#define Module_cnt	(Config_base + 8)
+#define Module_no	(Config_base + 10)
+#define Timer_10ms	(Config_base + 14)
+#define Disable_IRQ	(Config_base + 20)
+#define TMS320_PORT1	(Config_base + 22)
+#define TMS320_PORT2	(Config_base + 24)
+#define TMS320_CLOCK	(Config_base + 26)
+
+/*
+ *    DATA BUFFER in DRAM
+ */
+#define Extern_table	0x400	/* Base address of the external table
+				   (24 words *    64) total 3K bytes
+				   (24 words * 128) total 6K bytes */
+#define Extern_size	0x60	/* 96 bytes                       */
+#define RXrptr		0x00	/* read pointer for RX buffer     */
+#define RXwptr		0x02	/* write pointer for RX buffer    */
+#define TXrptr		0x04	/* read pointer for TX buffer     */
+#define TXwptr		0x06	/* write pointer for TX buffer    */
+#define HostStat	0x08	/* IRQ flag and general flag      */
+#define FlagStat	0x0A
+#define FlowControl	0x0C	/* B7 B6 B5 B4 B3 B2 B1 B0              */
+					/*  x  x  x  x  |  |  |  |            */
+					/*              |  |  |  + CTS flow   */
+					/*              |  |  +--- RTS flow   */
+					/*              |  +------ TX Xon/Xoff */
+					/*              +--------- RX Xon/Xoff */
+#define Break_cnt	0x0E	/* received break count   */
+#define CD180TXirq	0x10	/* if non-0: enable TX irq        */
+#define RX_mask 	0x12
+#define TX_mask 	0x14
+#define Ofs_rxb 	0x16
+#define Ofs_txb 	0x18
+#define Page_rxb	0x1A
+#define Page_txb	0x1C
+#define EndPage_rxb	0x1E
+#define EndPage_txb	0x20
+#define Data_error	0x22
+#define RxTrigger	0x28
+#define TxTrigger	0x2a
+
+#define rRXwptr 	0x34
+#define Low_water	0x36
+
+#define FuncCode	0x40
+#define FuncArg 	0x42
+#define FuncArg1	0x44
+
+#define C218rx_size	0x2000	/* 8K bytes */
+#define C218tx_size	0x8000	/* 32K bytes */
+
+#define C218rx_mask	(C218rx_size - 1)
+#define C218tx_mask	(C218tx_size - 1)
+
+#define C320p8rx_size	0x2000
+#define C320p8tx_size	0x8000
+#define C320p8rx_mask	(C320p8rx_size - 1)
+#define C320p8tx_mask	(C320p8tx_size - 1)
+
+#define C320p16rx_size	0x2000
+#define C320p16tx_size	0x4000
+#define C320p16rx_mask	(C320p16rx_size - 1)
+#define C320p16tx_mask	(C320p16tx_size - 1)
+
+#define C320p24rx_size	0x2000
+#define C320p24tx_size	0x2000
+#define C320p24rx_mask	(C320p24rx_size - 1)
+#define C320p24tx_mask	(C320p24tx_size - 1)
+
+#define C320p32rx_size	0x1000
+#define C320p32tx_size	0x1000
+#define C320p32rx_mask	(C320p32rx_size - 1)
+#define C320p32tx_mask	(C320p32tx_size - 1)
+
+#define Page_size	0x2000
+#define Page_mask	(Page_size - 1)
+#define C218rx_spage	3
+#define C218tx_spage	4
+#define C218rx_pageno	1
+#define C218tx_pageno	4
+#define C218buf_pageno	5
+
+#define C320p8rx_spage	3
+#define C320p8tx_spage	4
+#define C320p8rx_pgno	1
+#define C320p8tx_pgno	4
+#define C320p8buf_pgno	5
+
+#define C320p16rx_spage 3
+#define C320p16tx_spage 4
+#define C320p16rx_pgno	1
+#define C320p16tx_pgno	2
+#define C320p16buf_pgno 3
+
+#define C320p24rx_spage 3
+#define C320p24tx_spage 4
+#define C320p24rx_pgno	1
+#define C320p24tx_pgno	1
+#define C320p24buf_pgno 2
+
+#define C320p32rx_spage 3
+#define C320p32tx_ofs	C320p32rx_size
+#define C320p32tx_spage 3
+#define C320p32buf_pgno 1
+
+/*
+ *    Host Status
+ */
+#define WakeupRx	0x01
+#define WakeupTx	0x02
+#define WakeupBreak	0x08
+#define WakeupLine	0x10
+#define WakeupIntr	0x20
+#define WakeupQuit	0x40
+#define WakeupEOF	0x80	/* used in VTIME control */
+#define WakeupRxTrigger	0x100
+#define WakeupTxTrigger	0x200
+/*
+ *    Flag status
+ */
+#define Rx_over		0x01
+#define Xoff_state	0x02
+#define Tx_flowOff	0x04
+#define Tx_enable	0x08
+#define CTS_state	0x10
+#define DSR_state	0x20
+#define DCD_state	0x80
+/*
+ *    FlowControl
+ */
+#define CTS_FlowCtl	1
+#define RTS_FlowCtl	2
+#define Tx_FlowCtl	4
+#define Rx_FlowCtl	8
+#define IXM_IXANY	0x10
+
+#define LowWater	128
+
+#define DTR_ON		1
+#define RTS_ON		2
+#define CTS_ON		1
+#define DSR_ON		2
+#define DCD_ON		8
+
+/* mode definition */
+#define	MX_CS8		0x03
+#define	MX_CS7		0x02
+#define	MX_CS6		0x01
+#define	MX_CS5		0x00
+
+#define	MX_STOP1	0x00
+#define	MX_STOP15	0x04
+#define	MX_STOP2	0x08
+
+#define	MX_PARNONE	0x00
+#define	MX_PAREVEN	0x40
+#define	MX_PARODD	0xC0
+
+/*
+ *    Query
+ */
+#define QueryPort	MAX_PORTS
+
+
+
+struct mon_str {
+	int tick;
+	int rxcnt[MAX_PORTS];
+	int txcnt[MAX_PORTS];
+};
+typedef struct mon_str mon_st;
+
+#define 	DCD_changed	0x01
+#define 	DCD_oldstate	0x80
+
+static unsigned char moxaBuff[10240];
+static unsigned long moxaIntNdx[MAX_BOARDS];
+static unsigned long moxaIntPend[MAX_BOARDS];
+static unsigned long moxaIntTable[MAX_BOARDS];
+static char moxaChkPort[MAX_PORTS];
+static char moxaLineCtrl[MAX_PORTS];
+static unsigned long moxaTableAddr[MAX_PORTS];
+static long moxaCurBaud[MAX_PORTS];
+static char moxaDCDState[MAX_PORTS];
+static char moxaLowChkFlag[MAX_PORTS];
+static int moxaLowWaterChk;
+static int moxaCard;
+static mon_st moxaLog;
+static int moxaFuncTout;
+static ushort moxaBreakCnt[MAX_PORTS];
+
+static void moxadelay(int);
+static void moxafunc(unsigned long, int, ushort);
+static void wait_finish(unsigned long);
+static void low_water_check(unsigned long);
+static int moxaloadbios(int, unsigned char *, int);
+static int moxafindcard(int);
+static int moxaload320b(int, unsigned char *, int);
+static int moxaloadcode(int, unsigned char *, int);
+static int moxaloadc218(int, unsigned long, int);
+static int moxaloadc320(int, unsigned long, int, int *);
+
+/*****************************************************************************
+ *	Driver level functions: 					     *
+ *	1. MoxaDriverInit(void);					     *
+ *	2. MoxaDriverIoctl(unsigned int cmd, unsigned long arg, int port);   *
+ *	3. MoxaDriverPoll(void);					     *
+ *****************************************************************************/
+void MoxaDriverInit(void)
+{
+	int i;
+
+	moxaFuncTout = HZ / 2;	/* 500 mini-seconds */
+	moxaCard = 0;
+	moxaLog.tick = 0;
+	moxaLowWaterChk = 0;
+	for (i = 0; i < MAX_PORTS; i++) {
+		moxaChkPort[i] = 0;
+		moxaLowChkFlag[i] = 0;
+		moxaLineCtrl[i] = 0;
+		moxaLog.rxcnt[i] = 0;
+		moxaLog.txcnt[i] = 0;
+	}
+}
+
+#define	MOXA		0x400
+#define MOXA_GET_IQUEUE 	(MOXA + 1)	/* get input buffered count */
+#define MOXA_GET_OQUEUE 	(MOXA + 2)	/* get output buffered count */
+#define MOXA_INIT_DRIVER	(MOXA + 6)	/* moxaCard=0 */
+#define MOXA_LOAD_BIOS		(MOXA + 9)	/* download BIOS */
+#define MOXA_FIND_BOARD		(MOXA + 10)	/* Check if MOXA card exist? */
+#define MOXA_LOAD_C320B		(MOXA + 11)	/* download 320B firmware */
+#define MOXA_LOAD_CODE		(MOXA + 12)	/* download firmware */
+#define MOXA_GETDATACOUNT       (MOXA + 23)
+#define MOXA_GET_IOQUEUE	(MOXA + 27)
+#define MOXA_FLUSH_QUEUE	(MOXA + 28)
+#define MOXA_GET_CONF		(MOXA + 35)	/* configuration */
+#define MOXA_GET_MAJOR          (MOXA + 63)
+#define MOXA_GET_CUMAJOR        (MOXA + 64)
+#define MOXA_GETMSTATUS         (MOXA + 65)
+
+
+struct moxaq_str {
+	int inq;
+	int outq;
+};
+
+struct dl_str {
+	char *buf;
+	int len;
+	int cardno;
+};
+
+static struct moxaq_str temp_queue[MAX_PORTS];
+static struct dl_str dltmp;
+
+void MoxaPortFlushData(int port, int mode)
+{
+	unsigned long ofsAddr;
+	if ((mode < 0) || (mode > 2))
+		return;
+	ofsAddr = moxaTableAddr[port];
+	moxafunc(ofsAddr, FC_FlushQueue, mode);
+	if (mode != 1) {
+		moxaLowChkFlag[port] = 0;
+		low_water_check(ofsAddr);
+	}
+}
+
+int MoxaDriverIoctl(unsigned int cmd, unsigned long arg, int port)
+{
+	int i;
+	int status;
+	int MoxaPortTxQueue(int), MoxaPortRxQueue(int);
+
+	if (port == QueryPort) {
+		if ((cmd != MOXA_GET_CONF) && (cmd != MOXA_INIT_DRIVER) &&
+		    (cmd != MOXA_LOAD_BIOS) && (cmd != MOXA_FIND_BOARD) && (cmd != MOXA_LOAD_C320B) &&
+		 (cmd != MOXA_LOAD_CODE) && (cmd != MOXA_GETDATACOUNT) &&
+		  (cmd != MOXA_GET_IOQUEUE) && (cmd != MOXA_GET_MAJOR) &&
+		    (cmd != MOXA_GET_CUMAJOR) && (cmd != MOXA_GETMSTATUS))
+			return (-EINVAL);
+	}
+	switch (cmd) {
+	case MOXA_GET_CONF:
+		if(copy_to_user((void *)arg, &moxa_boards, MAX_BOARDS * sizeof(moxa_board_conf)))
+			return -EFAULT;
+		return (0);
+	case MOXA_INIT_DRIVER:
+		if ((int) arg == 0x404)
+			MoxaDriverInit();
+		return (0);
+	case MOXA_GETDATACOUNT:
+		moxaLog.tick = jiffies;
+		if(copy_to_user((void *)arg, &moxaLog, sizeof(mon_st)))
+			return -EFAULT;
+		return (0);
+	case MOXA_FLUSH_QUEUE:
+		MoxaPortFlushData(port, arg);
+		return (0);
+	case MOXA_GET_IOQUEUE:
+		for (i = 0; i < MAX_PORTS; i++) {
+			if (moxaChkPort[i]) {
+				temp_queue[i].inq = MoxaPortRxQueue(i);
+				temp_queue[i].outq = MoxaPortTxQueue(i);
+			}
+		}
+		if(copy_to_user((void *)arg, temp_queue, sizeof(struct moxaq_str) * MAX_PORTS))
+			return -EFAULT;
+		return (0);
+	case MOXA_LOAD_BIOS:
+		if(copy_from_user(&dltmp, (void *)arg, sizeof(struct dl_str)))
+			return -EFAULT;
+		i = moxaloadbios(dltmp.cardno, dltmp.buf, dltmp.len);
+		return (i);
+	case MOXA_FIND_BOARD:
+		if(copy_from_user(&dltmp, (void *)arg, sizeof(struct dl_str)))
+			return -EFAULT;
+		return moxafindcard(dltmp.cardno);
+	case MOXA_LOAD_C320B:
+		if(copy_from_user(&dltmp, (void *)arg, sizeof(struct dl_str)))
+			return -EFAULT;
+		moxaload320b(dltmp.cardno, dltmp.buf, dltmp.len);
+		return (0);
+	case MOXA_LOAD_CODE:
+		if(copy_from_user(&dltmp, (void *)arg, sizeof(struct dl_str)))
+			return -EFAULT; 
+		i = moxaloadcode(dltmp.cardno, dltmp.buf, dltmp.len);
+		if (i == -1)
+			return (-EFAULT);
+		return (i);
+	case MOXA_GET_OQUEUE:
+		i = MoxaPortTxQueue(port);
+		return put_user(i, (unsigned long *) arg);
+	case MOXA_GET_IQUEUE:
+		i = MoxaPortRxQueue(port);
+		return put_user(i, (unsigned long *) arg);
+	case MOXA_GET_MAJOR:
+		if(copy_to_user((void *)arg, &ttymajor, sizeof(int)))
+			return -EFAULT;
+		return 0;
+	case MOXA_GET_CUMAJOR:
+		if(copy_to_user((void *)arg, &calloutmajor, sizeof(int)))
+			return -EFAULT;
+		return 0;
+	case MOXA_GETMSTATUS:
+		for (i = 0; i < MAX_PORTS; i++) {
+			GMStatus[i].ri = 0;
+			GMStatus[i].dcd = 0;
+			GMStatus[i].dsr = 0;
+			GMStatus[i].cts = 0;
+			if (!moxaChkPort[i]) {
+				continue;
+			} else {
+				status = MoxaPortLineStatus(moxaChannels[i].port);
+				if (status & 1)
+					GMStatus[i].cts = 1;
+				if (status & 2)
+					GMStatus[i].dsr = 1;
+				if (status & 4)
+					GMStatus[i].dcd = 1;
+			}
+
+			if (!moxaChannels[i].tty || !moxaChannels[i].tty->termios)
+				GMStatus[i].cflag = moxaChannels[i].normal_termios.c_cflag;
+			else
+				GMStatus[i].cflag = moxaChannels[i].tty->termios->c_cflag;
+		}
+		if(copy_to_user((void *)arg, GMStatus, sizeof(struct mxser_mstatus) * MAX_PORTS))
+			return -EFAULT;
+		return 0;
+
+	}
+	return (-ENOIOCTLCMD);
+}
+
+int MoxaDriverPoll(void)
+{
+	register ushort temp;
+	register int card;
+	unsigned long ip, ofsAddr;
+	int port, p, ports;
+
+	if (moxaCard == 0)
+		return (-1);
+	for (card = 0; card < MAX_BOARDS; card++) {
+		if ((ports = moxa_boards[card].numPorts) == 0)
+			continue;
+		if (readb(moxaIntPend[card]) == 0xff) {
+			ip = moxaIntTable[card] + readb(moxaIntNdx[card]);
+			p = card * MAX_PORTS_PER_BOARD;
+			ports <<= 1;
+			for (port = 0; port < ports; port += 2, p++) {
+				if ((temp = readw(ip + port)) != 0) {
+					writew(0, ip + port);
+					ofsAddr = moxaTableAddr[p];
+					if (temp & IntrTx)
+						writew(readw(ofsAddr + HostStat) & ~WakeupTx, ofsAddr + HostStat);
+					if (temp & IntrBreak) {
+						moxaBreakCnt[p]++;
+					}
+					if (temp & IntrLine) {
+						if (readb(ofsAddr + FlagStat) & DCD_state) {
+							if ((moxaDCDState[p] & DCD_oldstate) == 0)
+								moxaDCDState[p] = (DCD_oldstate |
+										   DCD_changed);
+						} else {
+							if (moxaDCDState[p] & DCD_oldstate)
+								moxaDCDState[p] = DCD_changed;
+						}
+					}
+				}
+			}
+			writeb(0, moxaIntPend[card]);
+		}
+		if (moxaLowWaterChk) {
+			p = card * MAX_PORTS_PER_BOARD;
+			for (port = 0; port < ports; port++, p++) {
+				if (moxaLowChkFlag[p]) {
+					moxaLowChkFlag[p] = 0;
+					ofsAddr = moxaTableAddr[p];
+					low_water_check(ofsAddr);
+				}
+			}
+		}
+	}
+	moxaLowWaterChk = 0;
+	return (0);
+}
+
+/*****************************************************************************
+ *	Card level function:						     *
+ *	1. MoxaPortsOfCard(int cardno); 				     *
+ *****************************************************************************/
+int MoxaPortsOfCard(int cardno)
+{
+
+	if (moxa_boards[cardno].boardType == 0)
+		return (0);
+	return (moxa_boards[cardno].numPorts);
+}
+
+/*****************************************************************************
+ *	Port level functions:						     *
+ *	1.  MoxaPortIsValid(int port);					     *
+ *	2.  MoxaPortEnable(int port);					     *
+ *	3.  MoxaPortDisable(int port);					     *
+ *	4.  MoxaPortGetMaxBaud(int port);				     *
+ *	5.  MoxaPortGetCurBaud(int port);				     *
+ *	6.  MoxaPortSetBaud(int port, long baud);			     *
+ *	7.  MoxaPortSetMode(int port, int databit, int stopbit, int parity); *
+ *	8.  MoxaPortSetTermio(int port, unsigned char *termio); 	     *
+ *	9.  MoxaPortGetLineOut(int port, int *dtrState, int *rtsState);      *
+ *	10. MoxaPortLineCtrl(int port, int dtrState, int rtsState);	     *
+ *	11. MoxaPortFlowCtrl(int port, int rts, int cts, int rx, int tx,int xany);    *
+ *	12. MoxaPortLineStatus(int port);				     *
+ *	13. MoxaPortDCDChange(int port);				     *
+ *	14. MoxaPortDCDON(int port);					     *
+ *	15. MoxaPortFlushData(int port, int mode);	                     *
+ *	16. MoxaPortWriteData(int port, unsigned char * buffer, int length); *
+ *	17. MoxaPortReadData(int port, unsigned char * buffer, int length);  *
+ *	18. MoxaPortTxBufSize(int port);				     *
+ *	19. MoxaPortRxBufSize(int port);				     *
+ *	20. MoxaPortTxQueue(int port);					     *
+ *	21. MoxaPortTxFree(int port);					     *
+ *	22. MoxaPortRxQueue(int port);					     *
+ *	23. MoxaPortRxFree(int port);					     *
+ *	24. MoxaPortTxDisable(int port);				     *
+ *	25. MoxaPortTxEnable(int port); 				     *
+ *	26. MoxaPortGetBrkCnt(int port);				     *
+ *	27. MoxaPortResetBrkCnt(int port);				     *
+ *	28. MoxaPortSetXonXoff(int port, int xonValue, int xoffValue);	     *
+ *	29. MoxaPortIsTxHold(int port); 				     *
+ *	30. MoxaPortSendBreak(int port, int ticks);			     *
+ *****************************************************************************/
+/*
+ *    Moxa Port Number Description:
+ *
+ *      MOXA serial driver supports up to 4 MOXA-C218/C320 boards. And,
+ *      the port number using in MOXA driver functions will be 0 to 31 for
+ *      first MOXA board, 32 to 63 for second, 64 to 95 for third and 96
+ *      to 127 for fourth. For example, if you setup three MOXA boards,
+ *      first board is C218, second board is C320-16 and third board is
+ *      C320-32. The port number of first board (C218 - 8 ports) is from
+ *      0 to 7. The port number of second board (C320 - 16 ports) is form
+ *      32 to 47. The port number of third board (C320 - 32 ports) is from
+ *      64 to 95. And those port numbers form 8 to 31, 48 to 63 and 96 to
+ *      127 will be invalid.
+ *
+ *
+ *      Moxa Functions Description:
+ *
+ *      Function 1:     Driver initialization routine, this routine must be
+ *                      called when initialized driver.
+ *      Syntax:
+ *      void MoxaDriverInit();
+ *
+ *
+ *      Function 2:     Moxa driver private IOCTL command processing.
+ *      Syntax:
+ *      int  MoxaDriverIoctl(unsigned int cmd, unsigned long arg, int port);
+ *
+ *           unsigned int cmd   : IOCTL command
+ *           unsigned long arg  : IOCTL argument
+ *           int port           : port number (0 - 127)
+ *
+ *           return:    0  (OK)
+ *                      -EINVAL
+ *                      -ENOIOCTLCMD
+ *
+ *
+ *      Function 3:     Moxa driver polling process routine.
+ *      Syntax:
+ *      int  MoxaDriverPoll(void);
+ *
+ *           return:    0       ; polling O.K.
+ *                      -1      : no any Moxa card.             
+ *
+ *
+ *      Function 4:     Get the ports of this card.
+ *      Syntax:
+ *      int  MoxaPortsOfCard(int cardno);
+ *
+ *           int cardno         : card number (0 - 3)
+ *
+ *           return:    0       : this card is invalid
+ *                      8/16/24/32
+ *
+ *
+ *      Function 5:     Check this port is valid or invalid
+ *      Syntax:
+ *      int  MoxaPortIsValid(int port);
+ *           int port           : port number (0 - 127, ref port description)
+ *
+ *           return:    0       : this port is invalid
+ *                      1       : this port is valid
+ *
+ *
+ *      Function 6:     Enable this port to start Tx/Rx data.
+ *      Syntax:
+ *      void MoxaPortEnable(int port);
+ *           int port           : port number (0 - 127)
+ *
+ *
+ *      Function 7:     Disable this port
+ *      Syntax:
+ *      void MoxaPortDisable(int port);
+ *           int port           : port number (0 - 127)
+ *
+ *
+ *      Function 8:     Get the maximun available baud rate of this port.
+ *      Syntax:
+ *      long MoxaPortGetMaxBaud(int port);
+ *           int port           : port number (0 - 127)
+ *
+ *           return:    0       : this port is invalid
+ *                      38400/57600/115200 bps
+ *
+ *
+ *      Function 9:     Get the current baud rate of this port.
+ *      Syntax:
+ *      long MoxaPortGetCurBaud(int port);
+ *           int port           : port number (0 - 127)
+ *
+ *           return:    0       : this port is invalid
+ *                      50 - 115200 bps
+ *
+ *
+ *      Function 10:    Setting baud rate of this port.
+ *      Syntax:
+ *      long MoxaPortSetBaud(int port, long baud);
+ *           int port           : port number (0 - 127)
+ *           long baud          : baud rate (50 - 115200)
+ *
+ *           return:    0       : this port is invalid or baud < 50
+ *                      50 - 115200 : the real baud rate set to the port, if
+ *                                    the argument baud is large than maximun
+ *                                    available baud rate, the real setting
+ *                                    baud rate will be the maximun baud rate.
+ *
+ *
+ *      Function 11:    Setting the data-bits/stop-bits/parity of this port
+ *      Syntax:
+ *      int  MoxaPortSetMode(int port, int databits, int stopbits, int parity);
+ *           int port           : port number (0 - 127)
+ *           int databits       : data bits (8/7/6/5)
+ *           int stopbits       : stop bits (2/1/0, 0 show 1.5 stop bits)
+ int parity     : parity (0:None,1:Odd,2:Even,3:Mark,4:Space)
+ *
+ *           return:    -1      : invalid parameter
+ *                      0       : setting O.K.
+ *
+ *
+ *      Function 12:    Configure the port.
+ *      Syntax:
+ *      int  MoxaPortSetTermio(int port, struct termios *termio);
+ *           int port           : port number (0 - 127)
+ *           struct termios * termio : termio structure pointer
+ *
+ *           return:    -1      : this port is invalid or termio == NULL
+ *                      0       : setting O.K.
+ *
+ *
+ *      Function 13:    Get the DTR/RTS state of this port.
+ *      Syntax:
+ *      int  MoxaPortGetLineOut(int port, int *dtrState, int *rtsState);
+ *           int port           : port number (0 - 127)
+ *           int * dtrState     : pointer to INT to receive the current DTR
+ *                                state. (if NULL, this function will not
+ *                                write to this address)
+ *           int * rtsState     : pointer to INT to receive the current RTS
+ *                                state. (if NULL, this function will not
+ *                                write to this address)
+ *
+ *           return:    -1      : this port is invalid
+ *                      0       : O.K.
+ *
+ *
+ *      Function 14:    Setting the DTR/RTS output state of this port.
+ *      Syntax:
+ *      void MoxaPortLineCtrl(int port, int dtrState, int rtsState);
+ *           int port           : port number (0 - 127)
+ *           int dtrState       : DTR output state (0: off, 1: on)
+ *           int rtsState       : RTS output state (0: off, 1: on)
+ *
+ *
+ *      Function 15:    Setting the flow control of this port.
+ *      Syntax:
+ *      void MoxaPortFlowCtrl(int port, int rtsFlow, int ctsFlow, int rxFlow,
+ *                            int txFlow,int xany);
+ *           int port           : port number (0 - 127)
+ *           int rtsFlow        : H/W RTS flow control (0: no, 1: yes)
+ *           int ctsFlow        : H/W CTS flow control (0: no, 1: yes)
+ *           int rxFlow         : S/W Rx XON/XOFF flow control (0: no, 1: yes)
+ *           int txFlow         : S/W Tx XON/XOFF flow control (0: no, 1: yes)
+ *           int xany           : S/W XANY flow control (0: no, 1: yes)
+ *
+ *
+ *      Function 16:    Get ths line status of this port
+ *      Syntax:
+ *      int  MoxaPortLineStatus(int port);
+ *           int port           : port number (0 - 127)
+ *
+ *           return:    Bit 0 - CTS state (0: off, 1: on)
+ *                      Bit 1 - DSR state (0: off, 1: on)
+ *                      Bit 2 - DCD state (0: off, 1: on)
+ *
+ *
+ *      Function 17:    Check the DCD state has changed since the last read
+ *                      of this function.
+ *      Syntax:
+ *      int  MoxaPortDCDChange(int port);
+ *           int port           : port number (0 - 127)
+ *
+ *           return:    0       : no changed
+ *                      1       : DCD has changed
+ *
+ *
+ *      Function 18:    Check ths current DCD state is ON or not.
+ *      Syntax:
+ *      int  MoxaPortDCDON(int port);
+ *           int port           : port number (0 - 127)
+ *
+ *           return:    0       : DCD off
+ *                      1       : DCD on
+ *
+ *
+ *      Function 19:    Flush the Rx/Tx buffer data of this port.
+ *      Syntax:
+ *      void MoxaPortFlushData(int port, int mode);
+ *           int port           : port number (0 - 127)
+ *           int mode    
+ *                      0       : flush the Rx buffer 
+ *                      1       : flush the Tx buffer 
+ *                      2       : flush the Rx and Tx buffer 
+ *
+ *
+ *      Function 20:    Write data.
+ *      Syntax:
+ *      int  MoxaPortWriteData(int port, unsigned char * buffer, int length);
+ *           int port           : port number (0 - 127)
+ *           unsigned char * buffer     : pointer to write data buffer.
+ *           int length         : write data length
+ *
+ *           return:    0 - length      : real write data length
+ *
+ *
+ *      Function 21:    Read data.
+ *      Syntax:
+ *      int  MoxaPortReadData(int port, unsigned char * buffer, int length);
+ *           int port           : port number (0 - 127)
+ *           unsigned char * buffer     : pointer to read data buffer.
+ *           int length         : read data buffer length
+ *
+ *           return:    0 - length      : real read data length
+ *
+ *
+ *      Function 22:    Get the Tx buffer size of this port
+ *      Syntax:
+ *      int  MoxaPortTxBufSize(int port);
+ *           int port           : port number (0 - 127)
+ *
+ *           return:    ..      : Tx buffer size
+ *
+ *
+ *      Function 23:    Get the Rx buffer size of this port
+ *      Syntax:
+ *      int  MoxaPortRxBufSize(int port);
+ *           int port           : port number (0 - 127)
+ *
+ *           return:    ..      : Rx buffer size
+ *
+ *
+ *      Function 24:    Get the Tx buffer current queued data bytes
+ *      Syntax:
+ *      int  MoxaPortTxQueue(int port);
+ *           int port           : port number (0 - 127)
+ *
+ *           return:    ..      : Tx buffer current queued data bytes
+ *
+ *
+ *      Function 25:    Get the Tx buffer current free space
+ *      Syntax:
+ *      int  MoxaPortTxFree(int port);
+ *           int port           : port number (0 - 127)
+ *
+ *           return:    ..      : Tx buffer current free space
+ *
+ *
+ *      Function 26:    Get the Rx buffer current queued data bytes
+ *      Syntax:
+ *      int  MoxaPortRxQueue(int port);
+ *           int port           : port number (0 - 127)
+ *
+ *           return:    ..      : Rx buffer current queued data bytes
+ *
+ *
+ *      Function 27:    Get the Rx buffer current free space
+ *      Syntax:
+ *      int  MoxaPortRxFree(int port);
+ *           int port           : port number (0 - 127)
+ *
+ *           return:    ..      : Rx buffer current free space
+ *
+ *
+ *      Function 28:    Disable port data transmission.
+ *      Syntax:
+ *      void MoxaPortTxDisable(int port);
+ *           int port           : port number (0 - 127)
+ *
+ *
+ *      Function 29:    Enable port data transmission.
+ *      Syntax:
+ *      void MoxaPortTxEnable(int port);
+ *           int port           : port number (0 - 127)
+ *
+ *
+ *      Function 30:    Get the received BREAK signal count.
+ *      Syntax:
+ *      int  MoxaPortGetBrkCnt(int port);
+ *           int port           : port number (0 - 127)
+ *
+ *           return:    0 - ..  : BREAK signal count
+ *
+ *
+ *      Function 31:    Get the received BREAK signal count and reset it.
+ *      Syntax:
+ *      int  MoxaPortResetBrkCnt(int port);
+ *           int port           : port number (0 - 127)
+ *
+ *           return:    0 - ..  : BREAK signal count
+ *
+ *
+ *      Function 32:    Set the S/W flow control new XON/XOFF value, default
+ *                      XON is 0x11 & XOFF is 0x13.
+ *      Syntax:
+ *      void MoxaPortSetXonXoff(int port, int xonValue, int xoffValue);
+ *           int port           : port number (0 - 127)
+ *           int xonValue       : new XON value (0 - 255)
+ *           int xoffValue      : new XOFF value (0 - 255)
+ *
+ *
+ *      Function 33:    Check this port's transmission is hold by remote site
+ *                      because the flow control.
+ *      Syntax:
+ *      int  MoxaPortIsTxHold(int port);
+ *           int port           : port number (0 - 127)
+ *
+ *           return:    0       : normal
+ *                      1       : hold by remote site
+ *
+ *
+ *      Function 34:    Send out a BREAK signal.
+ *      Syntax:
+ *      void MoxaPortSendBreak(int port, int ms100);
+ *           int port           : port number (0 - 127)
+ *           int ms100          : break signal time interval.
+ *                                unit: 100 mini-second. if ms100 == 0, it will
+ *                                send out a about 250 ms BREAK signal.
+ *
+ */
+int MoxaPortIsValid(int port)
+{
+
+	if (moxaCard == 0)
+		return (0);
+	if (moxaChkPort[port] == 0)
+		return (0);
+	return (1);
+}
+
+void MoxaPortEnable(int port)
+{
+	unsigned long ofsAddr;
+	int MoxaPortLineStatus(int);
+	short lowwater = 512;
+
+	ofsAddr = moxaTableAddr[port];
+	writew(lowwater, ofsAddr + Low_water);
+	moxaBreakCnt[port] = 0;
+	if ((moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_ISA) ||
+	    (moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_PCI)) {
+		moxafunc(ofsAddr, FC_SetBreakIrq, 0);
+	} else {
+		writew(readw(ofsAddr + HostStat) | WakeupBreak, ofsAddr + HostStat);
+	}
+
+	moxafunc(ofsAddr, FC_SetLineIrq, Magic_code);
+	moxafunc(ofsAddr, FC_FlushQueue, 2);
+
+	moxafunc(ofsAddr, FC_EnableCH, Magic_code);
+	MoxaPortLineStatus(port);
+}
+
+void MoxaPortDisable(int port)
+{
+	unsigned long ofsAddr;
+
+	ofsAddr = moxaTableAddr[port];
+	moxafunc(ofsAddr, FC_SetFlowCtl, 0);	/* disable flow control */
+	moxafunc(ofsAddr, FC_ClrLineIrq, Magic_code);
+	writew(0, ofsAddr + HostStat);
+	moxafunc(ofsAddr, FC_DisableCH, Magic_code);
+}
+
+long MoxaPortGetMaxBaud(int port)
+{
+	if ((moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_ISA) ||
+	    (moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_PCI))
+		return (460800L);
+	else
+		return (921600L);
+}
+
+
+long MoxaPortSetBaud(int port, long baud)
+{
+	unsigned long ofsAddr;
+	long max, clock;
+	unsigned int val;
+
+	if ((baud < 50L) || ((max = MoxaPortGetMaxBaud(port)) == 0))
+		return (0);
+	ofsAddr = moxaTableAddr[port];
+	if (baud > max)
+		baud = max;
+	if (max == 38400L)
+		clock = 614400L;	/* for 9.8304 Mhz : max. 38400 bps */
+	else if (max == 57600L)
+		clock = 691200L;	/* for 11.0592 Mhz : max. 57600 bps */
+	else
+		clock = 921600L;	/* for 14.7456 Mhz : max. 115200 bps */
+	val = clock / baud;
+	moxafunc(ofsAddr, FC_SetBaud, val);
+	baud = clock / val;
+	moxaCurBaud[port] = baud;
+	return (baud);
+}
+
+int MoxaPortSetTermio(int port, struct termios *termio)
+{
+	unsigned long ofsAddr;
+	tcflag_t cflag;
+	long baud;
+	tcflag_t mode = 0;
+
+	if (moxaChkPort[port] == 0 || termio == 0)
+		return (-1);
+	ofsAddr = moxaTableAddr[port];
+	cflag = termio->c_cflag;	/* termio->c_cflag */
+
+	mode = termio->c_cflag & CSIZE;
+	if (mode == CS5)
+		mode = MX_CS5;
+	else if (mode == CS6)
+		mode = MX_CS6;
+	else if (mode == CS7)
+		mode = MX_CS7;
+	else if (mode == CS8)
+		mode = MX_CS8;
+
+	if (termio->c_cflag & CSTOPB) {
+		if (mode == MX_CS5)
+			mode |= MX_STOP15;
+		else
+			mode |= MX_STOP2;
+	} else
+		mode |= MX_STOP1;
+
+	if (termio->c_cflag & PARENB) {
+		if (termio->c_cflag & PARODD)
+			mode |= MX_PARODD;
+		else
+			mode |= MX_PAREVEN;
+	} else
+		mode |= MX_PARNONE;
+
+	moxafunc(ofsAddr, FC_SetDataMode, (ushort) mode);
+
+	cflag &= (CBAUD | CBAUDEX);
+#ifndef B921600
+#define	B921600	(B460800+1)
+#endif
+	switch (cflag) {
+	case B921600:
+		baud = 921600L;
+		break;
+	case B460800:
+		baud = 460800L;
+		break;
+	case B230400:
+		baud = 230400L;
+		break;
+	case B115200:
+		baud = 115200L;
+		break;
+	case B57600:
+		baud = 57600L;
+		break;
+	case B38400:
+		baud = 38400L;
+		break;
+	case B19200:
+		baud = 19200L;
+		break;
+	case B9600:
+		baud = 9600L;
+		break;
+	case B4800:
+		baud = 4800L;
+		break;
+	case B2400:
+		baud = 2400L;
+		break;
+	case B1800:
+		baud = 1800L;
+		break;
+	case B1200:
+		baud = 1200L;
+		break;
+	case B600:
+		baud = 600L;
+		break;
+	case B300:
+		baud = 300L;
+		break;
+	case B200:
+		baud = 200L;
+		break;
+	case B150:
+		baud = 150L;
+		break;
+	case B134:
+		baud = 134L;
+		break;
+	case B110:
+		baud = 110L;
+		break;
+	case B75:
+		baud = 75L;
+		break;
+	case B50:
+		baud = 50L;
+		break;
+	default:
+		baud = 0;
+	}
+	if ((moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_ISA) ||
+	    (moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_PCI)) {
+		if (baud == 921600L)
+			return (-1);
+	}
+	MoxaPortSetBaud(port, baud);
+
+	if (termio->c_iflag & (IXON | IXOFF | IXANY)) {
+		writeb(termio->c_cc[VSTART], ofsAddr + FuncArg);
+		writeb(termio->c_cc[VSTOP], ofsAddr + FuncArg1);
+		writeb(FC_SetXonXoff, ofsAddr + FuncCode);
+		wait_finish(ofsAddr);
+
+	}
+	return (0);
+}
+
+int MoxaPortGetLineOut(int port, int *dtrState, int *rtsState)
+{
+
+	if (!MoxaPortIsValid(port))
+		return (-1);
+	if (dtrState) {
+		if (moxaLineCtrl[port] & DTR_ON)
+			*dtrState = 1;
+		else
+			*dtrState = 0;
+	}
+	if (rtsState) {
+		if (moxaLineCtrl[port] & RTS_ON)
+			*rtsState = 1;
+		else
+			*rtsState = 0;
+	}
+	return (0);
+}
+
+void MoxaPortLineCtrl(int port, int dtr, int rts)
+{
+	unsigned long ofsAddr;
+	int mode;
+
+	ofsAddr = moxaTableAddr[port];
+	mode = 0;
+	if (dtr)
+		mode |= DTR_ON;
+	if (rts)
+		mode |= RTS_ON;
+	moxaLineCtrl[port] = mode;
+	moxafunc(ofsAddr, FC_LineControl, mode);
+}
+
+void MoxaPortFlowCtrl(int port, int rts, int cts, int txflow, int rxflow, int txany)
+{
+	unsigned long ofsAddr;
+	int mode;
+
+	ofsAddr = moxaTableAddr[port];
+	mode = 0;
+	if (rts)
+		mode |= RTS_FlowCtl;
+	if (cts)
+		mode |= CTS_FlowCtl;
+	if (txflow)
+		mode |= Tx_FlowCtl;
+	if (rxflow)
+		mode |= Rx_FlowCtl;
+	if (txany)
+		mode |= IXM_IXANY;
+	moxafunc(ofsAddr, FC_SetFlowCtl, mode);
+}
+
+int MoxaPortLineStatus(int port)
+{
+	unsigned long ofsAddr;
+	int val;
+
+	ofsAddr = moxaTableAddr[port];
+	if ((moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_ISA) ||
+	    (moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_PCI)) {
+		moxafunc(ofsAddr, FC_LineStatus, 0);
+		val = readw(ofsAddr + FuncArg);
+	} else {
+		val = readw(ofsAddr + FlagStat) >> 4;
+	}
+	val &= 0x0B;
+	if (val & 8) {
+		val |= 4;
+		if ((moxaDCDState[port] & DCD_oldstate) == 0)
+			moxaDCDState[port] = (DCD_oldstate | DCD_changed);
+	} else {
+		if (moxaDCDState[port] & DCD_oldstate)
+			moxaDCDState[port] = DCD_changed;
+	}
+	val &= 7;
+	return (val);
+}
+
+int MoxaPortDCDChange(int port)
+{
+	int n;
+
+	if (moxaChkPort[port] == 0)
+		return (0);
+	n = moxaDCDState[port];
+	moxaDCDState[port] &= ~DCD_changed;
+	n &= DCD_changed;
+	return (n);
+}
+
+int MoxaPortDCDON(int port)
+{
+	int n;
+
+	if (moxaChkPort[port] == 0)
+		return (0);
+	if (moxaDCDState[port] & DCD_oldstate)
+		n = 1;
+	else
+		n = 0;
+	return (n);
+}
+
+
+/*
+   int MoxaDumpMem(int port, unsigned char * buffer, int len)
+   {
+   int          i;
+   unsigned long                baseAddr,ofsAddr,ofs;
+
+   baseAddr = moxaBaseAddr[port / MAX_PORTS_PER_BOARD];
+   ofs = baseAddr + DynPage_addr + pageofs;
+   if (len > 0x2000L)
+   len = 0x2000L;
+   for (i = 0; i < len; i++)
+   buffer[i] = readb(ofs+i);
+   }
+ */
+
+
+int MoxaPortWriteData(int port, unsigned char * buffer, int len)
+{
+	int c, total, i;
+	ushort tail;
+	int cnt;
+	ushort head, tx_mask, spage, epage;
+	ushort pageno, pageofs, bufhead;
+	unsigned long baseAddr, ofsAddr, ofs;
+
+	ofsAddr = moxaTableAddr[port];
+	baseAddr = moxaBaseAddr[port / MAX_PORTS_PER_BOARD];
+	tx_mask = readw(ofsAddr + TX_mask);
+	spage = readw(ofsAddr + Page_txb);
+	epage = readw(ofsAddr + EndPage_txb);
+	tail = readw(ofsAddr + TXwptr);
+	head = readw(ofsAddr + TXrptr);
+	c = (head > tail) ? (head - tail - 1)
+	    : (head - tail + tx_mask);
+	if (c > len)
+		c = len;
+	moxaLog.txcnt[port] += c;
+	total = c;
+	if (spage == epage) {
+		bufhead = readw(ofsAddr + Ofs_txb);
+		writew(spage, baseAddr + Control_reg);
+		while (c > 0) {
+			if (head > tail)
+				len = head - tail - 1;
+			else
+				len = tx_mask + 1 - tail;
+			len = (c > len) ? len : c;
+			ofs = baseAddr + DynPage_addr + bufhead + tail;
+			for (i = 0; i < len; i++)
+				writeb(*buffer++, ofs + i);
+			tail = (tail + len) & tx_mask;
+			c -= len;
+		}
+		writew(tail, ofsAddr + TXwptr);
+	} else {
+		len = c;
+		pageno = spage + (tail >> 13);
+		pageofs = tail & Page_mask;
+		do {
+			cnt = Page_size - pageofs;
+			if (cnt > c)
+				cnt = c;
+			c -= cnt;
+			writeb(pageno, baseAddr + Control_reg);
+			ofs = baseAddr + DynPage_addr + pageofs;
+			for (i = 0; i < cnt; i++)
+				writeb(*buffer++, ofs + i);
+			if (c == 0) {
+				writew((tail + len) & tx_mask, ofsAddr + TXwptr);
+				break;
+			}
+			if (++pageno == epage)
+				pageno = spage;
+			pageofs = 0;
+		} while (1);
+	}
+	writeb(1, ofsAddr + CD180TXirq);	/* start to send */
+	return (total);
+}
+
+int MoxaPortReadData(int port, unsigned char * buffer, int space)
+{
+	register ushort head, pageofs;
+	int i, count, cnt, len, total, remain;
+	ushort tail, rx_mask, spage, epage;
+	ushort pageno, bufhead;
+	unsigned long baseAddr, ofsAddr, ofs;
+
+	ofsAddr = moxaTableAddr[port];
+	baseAddr = moxaBaseAddr[port / MAX_PORTS_PER_BOARD];
+	head = readw(ofsAddr + RXrptr);
+	tail = readw(ofsAddr + RXwptr);
+	rx_mask = readw(ofsAddr + RX_mask);
+	spage = readw(ofsAddr + Page_rxb);
+	epage = readw(ofsAddr + EndPage_rxb);
+	count = (tail >= head) ? (tail - head)
+	    : (tail - head + rx_mask + 1);
+	if (count == 0)
+		return (0);
+
+	total = (space > count) ? count : space;
+	remain = count - total;
+	moxaLog.rxcnt[port] += total;
+	count = total;
+	if (spage == epage) {
+		bufhead = readw(ofsAddr + Ofs_rxb);
+		writew(spage, baseAddr + Control_reg);
+		while (count > 0) {
+			if (tail >= head)
+				len = tail - head;
+			else
+				len = rx_mask + 1 - head;
+			len = (count > len) ? len : count;
+			ofs = baseAddr + DynPage_addr + bufhead + head;
+			for (i = 0; i < len; i++)
+				*buffer++ = readb(ofs + i);
+			head = (head + len) & rx_mask;
+			count -= len;
+		}
+		writew(head, ofsAddr + RXrptr);
+	} else {
+		len = count;
+		pageno = spage + (head >> 13);
+		pageofs = head & Page_mask;
+		do {
+			cnt = Page_size - pageofs;
+			if (cnt > count)
+				cnt = count;
+			count -= cnt;
+			writew(pageno, baseAddr + Control_reg);
+			ofs = baseAddr + DynPage_addr + pageofs;
+			for (i = 0; i < cnt; i++)
+				*buffer++ = readb(ofs + i);
+			if (count == 0) {
+				writew((head + len) & rx_mask, ofsAddr + RXrptr);
+				break;
+			}
+			if (++pageno == epage)
+				pageno = spage;
+			pageofs = 0;
+		} while (1);
+	}
+	if ((readb(ofsAddr + FlagStat) & Xoff_state) && (remain < LowWater)) {
+		moxaLowWaterChk = 1;
+		moxaLowChkFlag[port] = 1;
+	}
+	return (total);
+}
+
+
+int MoxaPortTxQueue(int port)
+{
+	unsigned long ofsAddr;
+	ushort rptr, wptr, mask;
+	int len;
+
+	ofsAddr = moxaTableAddr[port];
+	rptr = readw(ofsAddr + TXrptr);
+	wptr = readw(ofsAddr + TXwptr);
+	mask = readw(ofsAddr + TX_mask);
+	len = (wptr - rptr) & mask;
+	return (len);
+}
+
+int MoxaPortTxFree(int port)
+{
+	unsigned long ofsAddr;
+	ushort rptr, wptr, mask;
+	int len;
+
+	ofsAddr = moxaTableAddr[port];
+	rptr = readw(ofsAddr + TXrptr);
+	wptr = readw(ofsAddr + TXwptr);
+	mask = readw(ofsAddr + TX_mask);
+	len = mask - ((wptr - rptr) & mask);
+	return (len);
+}
+
+int MoxaPortRxQueue(int port)
+{
+	unsigned long ofsAddr;
+	ushort rptr, wptr, mask;
+	int len;
+
+	ofsAddr = moxaTableAddr[port];
+	rptr = readw(ofsAddr + RXrptr);
+	wptr = readw(ofsAddr + RXwptr);
+	mask = readw(ofsAddr + RX_mask);
+	len = (wptr - rptr) & mask;
+	return (len);
+}
+
+
+void MoxaPortTxDisable(int port)
+{
+	unsigned long ofsAddr;
+
+	ofsAddr = moxaTableAddr[port];
+	moxafunc(ofsAddr, FC_SetXoffState, Magic_code);
+}
+
+void MoxaPortTxEnable(int port)
+{
+	unsigned long ofsAddr;
+
+	ofsAddr = moxaTableAddr[port];
+	moxafunc(ofsAddr, FC_SetXonState, Magic_code);
+}
+
+
+int MoxaPortResetBrkCnt(int port)
+{
+	ushort cnt;
+	cnt = moxaBreakCnt[port];
+	moxaBreakCnt[port] = 0;
+	return (cnt);
+}
+
+
+void MoxaPortSendBreak(int port, int ms100)
+{
+	unsigned long ofsAddr;
+
+	ofsAddr = moxaTableAddr[port];
+	if (ms100) {
+		moxafunc(ofsAddr, FC_SendBreak, Magic_code);
+		moxadelay(ms100 * (HZ / 10));
+	} else {
+		moxafunc(ofsAddr, FC_SendBreak, Magic_code);
+		moxadelay(HZ / 4);	/* 250 ms */
+	}
+	moxafunc(ofsAddr, FC_StopBreak, Magic_code);
+}
+
+static int moxa_get_serial_info(struct moxa_str *info,
+				struct serial_struct *retinfo)
+{
+	struct serial_struct tmp;
+
+	if (!retinfo)
+		return (-EFAULT);
+	memset(&tmp, 0, sizeof(tmp));
+	tmp.type = info->type;
+	tmp.line = info->port;
+	tmp.port = 0;
+	tmp.irq = 0;
+	tmp.flags = info->asyncflags;
+	tmp.baud_base = 921600;
+	tmp.close_delay = info->close_delay;
+	tmp.closing_wait = info->closing_wait;
+	tmp.custom_divisor = 0;
+	tmp.hub6 = 0;
+	if(copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+		return -EFAULT;
+	return (0);
+}
+
+
+static int moxa_set_serial_info(struct moxa_str *info,
+				struct serial_struct *new_info)
+{
+	struct serial_struct new_serial;
+
+	if(copy_from_user(&new_serial, new_info, sizeof(new_serial)))
+		return -EFAULT;
+
+	if ((new_serial.irq != 0) ||
+	    (new_serial.port != 0) ||
+//           (new_serial.type != info->type) ||
+	    (new_serial.custom_divisor != 0) ||
+	    (new_serial.baud_base != 921600))
+		return (-EPERM);
+
+	if (!suser()) {
+		if (((new_serial.flags & ~ASYNC_USR_MASK) !=
+		     (info->asyncflags & ~ASYNC_USR_MASK)))
+			return (-EPERM);
+	} else {
+		info->close_delay = new_serial.close_delay * HZ / 100;
+		info->closing_wait = new_serial.closing_wait * HZ / 100;
+	}
+
+	new_serial.flags = (new_serial.flags & ~ASYNC_FLAGS);
+	new_serial.flags |= (info->asyncflags & ASYNC_FLAGS);
+
+	if (new_serial.type == PORT_16550A) {
+		MoxaSetFifo(info->port, 1);
+	} else {
+		MoxaSetFifo(info->port, 0);
+	}
+
+	info->type = new_serial.type;
+	return (0);
+}
+
+
+
+/*****************************************************************************
+ *	Static local functions: 					     *
+ *****************************************************************************/
+/*
+ * moxadelay - delays a specified number ticks
+ */
+static void moxadelay(int tick)
+{
+	unsigned long st, et;
+
+	st = jiffies;
+	et = st + tick;
+	while (jiffies < et);
+}
+
+static void moxafunc(unsigned long ofsAddr, int cmd, ushort arg)
+{
+
+	writew(arg, ofsAddr + FuncArg);
+	writew(cmd, ofsAddr + FuncCode);
+	wait_finish(ofsAddr);
+}
+
+static void wait_finish(unsigned long ofsAddr)
+{
+	unsigned long i, j;
+
+	i = jiffies;
+	while (readw(ofsAddr + FuncCode) != 0) {
+		j = jiffies;
+		if ((j - i) > moxaFuncTout) {
+			return;
+		}
+	}
+}
+
+static void low_water_check(unsigned long ofsAddr)
+{
+	int len;
+	ushort rptr, wptr, mask;
+
+	if (readb(ofsAddr + FlagStat) & Xoff_state) {
+		rptr = readw(ofsAddr + RXrptr);
+		wptr = readw(ofsAddr + RXwptr);
+		mask = readw(ofsAddr + RX_mask);
+		len = (wptr - rptr) & mask;
+		if (len <= Low_water)
+			moxafunc(ofsAddr, FC_SendXon, 0);
+	}
+}
+
+static int moxaloadbios(int cardno, unsigned char *tmp, int len)
+{
+	unsigned long baseAddr;
+	int i;
+
+	if(copy_from_user(moxaBuff, tmp, len))
+		return -EFAULT;
+	baseAddr = moxaBaseAddr[cardno];
+	writeb(HW_reset, baseAddr + Control_reg);	/* reset */
+	moxadelay(1);		/* delay 10 ms */
+	for (i = 0; i < 4096; i++)
+		writeb(0, baseAddr + i);	/* clear fix page */
+	for (i = 0; i < len; i++)
+		writeb(moxaBuff[i], baseAddr + i);	/* download BIOS */
+	writeb(0, baseAddr + Control_reg);	/* restart */
+	return (0);
+}
+
+static int moxafindcard(int cardno)
+{
+	unsigned long baseAddr;
+	ushort tmp;
+
+	baseAddr = moxaBaseAddr[cardno];
+	switch (moxa_boards[cardno].boardType) {
+	case MOXA_BOARD_C218_ISA:
+	case MOXA_BOARD_C218_PCI:
+		if ((tmp = readw(baseAddr + C218_key)) != C218_KeyCode) {
+			return (-1);
+		}
+		break;
+	case MOXA_BOARD_CP204J:
+		if ((tmp = readw(baseAddr + C218_key)) != CP204J_KeyCode) {
+			return (-1);
+		}
+		break;
+	default:
+		if ((tmp = readw(baseAddr + C320_key)) != C320_KeyCode) {
+			return (-1);
+		}
+		if ((tmp = readw(baseAddr + C320_status)) != STS_init) {
+			return (-2);
+		}
+	}
+	return (0);
+}
+
+static int moxaload320b(int cardno, unsigned char * tmp, int len)
+{
+	unsigned long baseAddr;
+	int i;
+
+	if(copy_from_user(moxaBuff, tmp, len))
+		return -EFAULT;
+	baseAddr = moxaBaseAddr[cardno];
+	writew(len - 7168 - 2, baseAddr + C320bapi_len);
+	writeb(1, baseAddr + Control_reg);	/* Select Page 1 */
+	for (i = 0; i < 7168; i++)
+		writeb(moxaBuff[i], baseAddr + DynPage_addr + i);
+	writeb(2, baseAddr + Control_reg);	/* Select Page 2 */
+	for (i = 0; i < (len - 7168); i++)
+		writeb(moxaBuff[i + 7168], baseAddr + DynPage_addr + i);
+	return (0);
+}
+
+static int moxaloadcode(int cardno, unsigned char * tmp, int len)
+{
+	unsigned long baseAddr, ofsAddr;
+	int retval, port, i;
+
+	if(copy_from_user(moxaBuff, tmp, len))
+		return -EFAULT;
+	baseAddr = moxaBaseAddr[cardno];
+	switch (moxa_boards[cardno].boardType) {
+	case MOXA_BOARD_C218_ISA:
+	case MOXA_BOARD_C218_PCI:
+	case MOXA_BOARD_CP204J:
+		retval = moxaloadc218(cardno, baseAddr, len);
+		if (retval)
+			return (retval);
+		port = cardno * MAX_PORTS_PER_BOARD;
+		for (i = 0; i < moxa_boards[cardno].numPorts; i++, port++) {
+			moxaChkPort[port] = 1;
+			moxaCurBaud[port] = 9600L;
+			moxaDCDState[port] = 0;
+			moxaTableAddr[port] = baseAddr + Extern_table + Extern_size * i;
+			ofsAddr = moxaTableAddr[port];
+			writew(C218rx_mask, ofsAddr + RX_mask);
+			writew(C218tx_mask, ofsAddr + TX_mask);
+			writew(C218rx_spage + i * C218buf_pageno, ofsAddr + Page_rxb);
+			writew(readw(ofsAddr + Page_rxb) + C218rx_pageno, ofsAddr + EndPage_rxb);
+
+			writew(C218tx_spage + i * C218buf_pageno, ofsAddr + Page_txb);
+			writew(readw(ofsAddr + Page_txb) + C218tx_pageno, ofsAddr + EndPage_txb);
+
+		}
+		break;
+	default:
+		retval = moxaloadc320(cardno, baseAddr, len,
+				      &moxa_boards[cardno].numPorts);
+		if (retval)
+			return (retval);
+		port = cardno * MAX_PORTS_PER_BOARD;
+		for (i = 0; i < moxa_boards[cardno].numPorts; i++, port++) {
+			moxaChkPort[port] = 1;
+			moxaCurBaud[port] = 9600L;
+			moxaDCDState[port] = 0;
+			moxaTableAddr[port] = baseAddr + Extern_table + Extern_size * i;
+			ofsAddr = moxaTableAddr[port];
+			if (moxa_boards[cardno].numPorts == 8) {
+				writew(C320p8rx_mask, ofsAddr + RX_mask);
+				writew(C320p8tx_mask, ofsAddr + TX_mask);
+				writew(C320p8rx_spage + i * C320p8buf_pgno, ofsAddr + Page_rxb);
+				writew(readw(ofsAddr + Page_rxb) + C320p8rx_pgno, ofsAddr + EndPage_rxb);
+				writew(C320p8tx_spage + i * C320p8buf_pgno, ofsAddr + Page_txb);
+				writew(readw(ofsAddr + Page_txb) + C320p8tx_pgno, ofsAddr + EndPage_txb);
+
+			} else if (moxa_boards[cardno].numPorts == 16) {
+				writew(C320p16rx_mask, ofsAddr + RX_mask);
+				writew(C320p16tx_mask, ofsAddr + TX_mask);
+				writew(C320p16rx_spage + i * C320p16buf_pgno, ofsAddr + Page_rxb);
+				writew(readw(ofsAddr + Page_rxb) + C320p16rx_pgno, ofsAddr + EndPage_rxb);
+				writew(C320p16tx_spage + i * C320p16buf_pgno, ofsAddr + Page_txb);
+				writew(readw(ofsAddr + Page_txb) + C320p16tx_pgno, ofsAddr + EndPage_txb);
+
+			} else if (moxa_boards[cardno].numPorts == 24) {
+				writew(C320p24rx_mask, ofsAddr + RX_mask);
+				writew(C320p24tx_mask, ofsAddr + TX_mask);
+				writew(C320p24rx_spage + i * C320p24buf_pgno, ofsAddr + Page_rxb);
+				writew(readw(ofsAddr + Page_rxb) + C320p24rx_pgno, ofsAddr + EndPage_rxb);
+				writew(C320p24tx_spage + i * C320p24buf_pgno, ofsAddr + Page_txb);
+				writew(readw(ofsAddr + Page_txb), ofsAddr + EndPage_txb);
+			} else if (moxa_boards[cardno].numPorts == 32) {
+				writew(C320p32rx_mask, ofsAddr + RX_mask);
+				writew(C320p32tx_mask, ofsAddr + TX_mask);
+				writew(C320p32tx_ofs, ofsAddr + Ofs_txb);
+				writew(C320p32rx_spage + i * C320p32buf_pgno, ofsAddr + Page_rxb);
+				writew(readb(ofsAddr + Page_rxb), ofsAddr + EndPage_rxb);
+				writew(C320p32tx_spage + i * C320p32buf_pgno, ofsAddr + Page_txb);
+				writew(readw(ofsAddr + Page_txb), ofsAddr + EndPage_txb);
+			}
+		}
+		break;
+	}
+	return (0);
+}
+
+static int moxaloadc218(int cardno, unsigned long baseAddr, int len)
+{
+	char retry;
+	int i, j, len1, len2;
+	ushort usum, *ptr, keycode;
+
+	if (moxa_boards[cardno].boardType == MOXA_BOARD_CP204J)
+		keycode = CP204J_KeyCode;
+	else
+		keycode = C218_KeyCode;
+	usum = 0;
+	len1 = len >> 1;
+	ptr = (ushort *) moxaBuff;
+	for (i = 0; i < len1; i++)
+		usum += *(ptr + i);
+	retry = 0;
+	do {
+		len1 = len >> 1;
+		j = 0;
+		while (len1) {
+			len2 = (len1 > 2048) ? 2048 : len1;
+			len1 -= len2;
+			for (i = 0; i < len2 << 1; i++)
+				writeb(moxaBuff[i + j], baseAddr + C218_LoadBuf + i);
+			j += i;
+
+			writew(len2, baseAddr + C218DLoad_len);
+			writew(0, baseAddr + C218_key);
+			for (i = 0; i < 100; i++) {
+				if (readw(baseAddr + C218_key) == keycode)
+					break;
+				moxadelay(1);	/* delay 10 ms */
+			}
+			if (readw(baseAddr + C218_key) != keycode) {
+				return (-1);
+			}
+		}
+		writew(0, baseAddr + C218DLoad_len);
+		writew(usum, baseAddr + C218check_sum);
+		writew(0, baseAddr + C218_key);
+		for (i = 0; i < 100; i++) {
+			if (readw(baseAddr + C218_key) == keycode)
+				break;
+			moxadelay(1);	/* delay 10 ms */
+		}
+		retry++;
+	} while ((readb(baseAddr + C218chksum_ok) != 1) && (retry < 3));
+	if (readb(baseAddr + C218chksum_ok) != 1) {
+		return (-1);
+	}
+	writew(0, baseAddr + C218_key);
+	for (i = 0; i < 100; i++) {
+		if (readw(baseAddr + Magic_no) == Magic_code)
+			break;
+		moxadelay(1);	/* delay 10 ms */
+	}
+	if (readw(baseAddr + Magic_no) != Magic_code) {
+		return (-1);
+	}
+	writew(1, baseAddr + Disable_IRQ);
+	writew(0, baseAddr + Magic_no);
+	for (i = 0; i < 100; i++) {
+		if (readw(baseAddr + Magic_no) == Magic_code)
+			break;
+		moxadelay(1);	/* delay 10 ms */
+	}
+	if (readw(baseAddr + Magic_no) != Magic_code) {
+		return (-1);
+	}
+	moxaCard = 1;
+	moxaIntNdx[cardno] = baseAddr + IRQindex;
+	moxaIntPend[cardno] = baseAddr + IRQpending;
+	moxaIntTable[cardno] = baseAddr + IRQtable;
+	return (0);
+}
+
+static int moxaloadc320(int cardno, unsigned long baseAddr, int len, int *numPorts)
+{
+	ushort usum;
+	int i, j, wlen, len2, retry;
+	ushort *uptr;
+
+	usum = 0;
+	wlen = len >> 1;
+	uptr = (ushort *) moxaBuff;
+	for (i = 0; i < wlen; i++)
+		usum += uptr[i];
+	retry = 0;
+	j = 0;
+	do {
+		while (wlen) {
+			if (wlen > 2048)
+				len2 = 2048;
+			else
+				len2 = wlen;
+			wlen -= len2;
+			len2 <<= 1;
+			for (i = 0; i < len2; i++)
+				writeb(moxaBuff[j + i], baseAddr + C320_LoadBuf + i);
+			len2 >>= 1;
+			j += i;
+			writew(len2, baseAddr + C320DLoad_len);
+			writew(0, baseAddr + C320_key);
+			for (i = 0; i < 10; i++) {
+				if (readw(baseAddr + C320_key) == C320_KeyCode)
+					break;
+				moxadelay(1);
+			}
+			if (readw(baseAddr + C320_key) != C320_KeyCode)
+				return (-1);
+		}
+		writew(0, baseAddr + C320DLoad_len);
+		writew(usum, baseAddr + C320check_sum);
+		writew(0, baseAddr + C320_key);
+		for (i = 0; i < 10; i++) {
+			if (readw(baseAddr + C320_key) == C320_KeyCode)
+				break;
+			moxadelay(1);
+		}
+		retry++;
+	} while ((readb(baseAddr + C320chksum_ok) != 1) && (retry < 3));
+	if (readb(baseAddr + C320chksum_ok) != 1)
+		return (-1);
+	writew(0, baseAddr + C320_key);
+	for (i = 0; i < 600; i++) {
+		if (readw(baseAddr + Magic_no) == Magic_code)
+			break;
+		moxadelay(1);
+	}
+	if (readw(baseAddr + Magic_no) != Magic_code)
+		return (-100);
+
+	if (moxa_boards[cardno].busType == MOXA_BUS_TYPE_PCI) {		/* ASIC board */
+		writew(0x3800, baseAddr + TMS320_PORT1);
+		writew(0x3900, baseAddr + TMS320_PORT2);
+		writew(28499, baseAddr + TMS320_CLOCK);
+	} else {
+		writew(0x3200, baseAddr + TMS320_PORT1);
+		writew(0x3400, baseAddr + TMS320_PORT2);
+		writew(19999, baseAddr + TMS320_CLOCK);
+	}
+	writew(1, baseAddr + Disable_IRQ);
+	writew(0, baseAddr + Magic_no);
+	for (i = 0; i < 500; i++) {
+		if (readw(baseAddr + Magic_no) == Magic_code)
+			break;
+		moxadelay(1);
+	}
+	if (readw(baseAddr + Magic_no) != Magic_code)
+		return (-102);
+
+	j = readw(baseAddr + Module_cnt);
+	if (j <= 0)
+		return (-101);
+	*numPorts = j * 8;
+	writew(j, baseAddr + Module_no);
+	writew(0, baseAddr + Magic_no);
+	for (i = 0; i < 600; i++) {
+		if (readw(baseAddr + Magic_no) == Magic_code)
+			break;
+		moxadelay(1);
+	}
+	if (readw(baseAddr + Magic_no) != Magic_code)
+		return (-102);
+	moxaCard = 1;
+	moxaIntNdx[cardno] = baseAddr + IRQindex;
+	moxaIntPend[cardno] = baseAddr + IRQpending;
+	moxaIntTable[cardno] = baseAddr + IRQtable;
+	return (0);
+}
+
+long MoxaPortGetCurBaud(int port)
+{
+
+	if (moxaChkPort[port] == 0)
+		return (0);
+	return (moxaCurBaud[port]);
+}
+
+static void MoxaSetFifo(int port, int enable)
+{
+	unsigned long ofsAddr = moxaTableAddr[port];
+
+	if (!enable) {
+		moxafunc(ofsAddr, FC_SetRxFIFOTrig, 0);
+		moxafunc(ofsAddr, FC_SetTxFIFOCnt, 1);
+	} else {
+		moxafunc(ofsAddr, FC_SetRxFIFOTrig, 3);
+		moxafunc(ofsAddr, FC_SetTxFIFOCnt, 16);
+	}
+}
+
+#if 0
+int MoxaPortSetMode(int port, int databits, int stopbits, int parity)
+{
+	unsigned long ofsAddr;
+	int val;
+
+	val = 0;
+	switch (databits) {
+	case 5:
+		val |= 0;
+		break;
+	case 6:
+		val |= 1;
+		break;
+	case 7:
+		val |= 2;
+		break;
+	case 8:
+		val |= 3;
+		break;
+	default:
+		return (-1);
+	}
+	switch (stopbits) {
+	case 0:
+		val |= 0;
+		break;		/* stop bits 1.5 */
+	case 1:
+		val |= 0;
+		break;
+	case 2:
+		val |= 4;
+		break;
+	default:
+		return (-1);
+	}
+	switch (parity) {
+	case 0:
+		val |= 0x00;
+		break;		/* None  */
+	case 1:
+		val |= 0x08;
+		break;		/* Odd   */
+	case 2:
+		val |= 0x18;
+		break;		/* Even  */
+	case 3:
+		val |= 0x28;
+		break;		/* Mark  */
+	case 4:
+		val |= 0x38;
+		break;		/* Space */
+	default:
+		return (-1);
+	}
+	ofsAddr = moxaTableAddr[port];
+	moxafunc(ofsAddr, FC_SetMode, val);
+	return (0);
+}
+
+int MoxaPortTxBufSize(int port)
+{
+	unsigned long ofsAddr;
+	int size;
+
+	ofsAddr = moxaTableAddr[port];
+	size = readw(ofsAddr + TX_mask);
+	return (size);
+}
+
+int MoxaPortRxBufSize(int port)
+{
+	unsigned long ofsAddr;
+	int size;
+
+	ofsAddr = moxaTableAddr[port];
+	size = readw(ofsAddr + RX_mask);
+	return (size);
+}
+
+int MoxaPortRxFree(int port)
+{
+	unsigned long ofsAddr;
+	ushort rptr, wptr, mask;
+	int len;
+
+	ofsAddr = moxaTableAddr[port];
+	rptr = readw(ofsAddr + RXrptr);
+	wptr = readw(ofsAddr + RXwptr);
+	mask = readw(ofsAddr + RX_mask);
+	len = mask - ((wptr - rptr) & mask);
+	return (len);
+}
+int MoxaPortGetBrkCnt(int port)
+{
+	return (moxaBreakCnt[port]);
+}
+
+void MoxaPortSetXonXoff(int port, int xonValue, int xoffValue)
+{
+	unsigned long ofsAddr;
+
+	ofsAddr = moxaTableAddr[port];
+	writew(xonValue, ofsAddr + FuncArg);
+	writew(xoffValue, ofsAddr + FuncArg1);
+	writew(FC_SetXonXoff, ofsAddr + FuncCode);
+	wait_finish(ofsAddr);
+}
+
+int MoxaPortIsTxHold(int port)
+{
+	unsigned long ofsAddr;
+	int val;
+
+	ofsAddr = moxaTableAddr[port];
+	if ((moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_ISA) ||
+	    (moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_PCI)) {
+		moxafunc(ofsAddr, FC_GetCCSR, 0);
+		val = readw(ofsAddr + FuncArg);
+		if (val & 0x04)
+			return (1);
+	} else {
+		if (readw(ofsAddr + FlagStat) & Tx_flowOff)
+			return (1);
+	}
+	return (0);
+}
+#endif
diff -urN linux-2.2.14-pre16/drivers/char/mxser.c linux-2.2.14-pre17/drivers/char/mxser.c
--- linux-2.2.14-pre16/drivers/char/mxser.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.2.14-pre17/drivers/char/mxser.c	2003-08-15 15:10:02.000000000 -0700
@@ -0,0 +1,2449 @@
+/*****************************************************************************/
+/*
+ *          mxser.c  -- MOXA Smartio family multiport serial driver.
+ *
+ *      Copyright (C) 1999-2000  Moxa Technologies (support@moxa.com.tw).
+ *
+ *      This code is loosely based on the Linux serial driver, written by
+ *      Linus Torvalds, Theodore T'so and others.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ *    MOXA Smartio Family Serial Driver
+ *
+ *      Copyright (C) 1999,2000  Moxa Technologies Co., LTD.
+ *
+ *      for             : LINUX 2.0.X, 2.2.X
+ *      date            : 1999/07/22
+ *      version         : 1.1 
+ *      
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/serial_reg.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/smp_lock.h>
+#include <linux/pci.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/segment.h>
+#include <asm/bitops.h>
+#include <asm/uaccess.h>
+
+#define		MXSER_VERSION			"1.1kern"
+
+#define		MXSERMAJOR	 	174
+#define		MXSERCUMAJOR		175
+
+
+#define	MXSER_EVENT_TXLOW	 1
+#define	MXSER_EVENT_HANGUP	 2
+
+
+#define 	SERIAL_DO_RESTART
+
+#define 	MXSER_BOARDS		4	/* Max. boards */
+#define 	MXSER_PORTS		32	/* Max. ports */
+#define 	MXSER_PORTS_PER_BOARD	8	/* Max. ports per board */
+#define 	MXSER_ISR_PASS_LIMIT	256
+
+#define		MXSER_ERR_IOADDR	-1
+#define		MXSER_ERR_IRQ		-2
+#define		MXSER_ERR_IRQ_CONFLIT	-3
+#define		MXSER_ERR_VECTOR	-4
+
+#define 	SERIAL_TYPE_NORMAL	1
+#define 	SERIAL_TYPE_CALLOUT	2
+
+#define 	WAKEUP_CHARS		256
+
+#define 	UART_MCR_AFE		0x20
+#define 	UART_LSR_SPECIAL	0x1E
+
+#define PORTNO(x)		(MINOR((x)->device) - (x)->driver.minor_start)
+
+#define RELEVANT_IFLAG(iflag)	(iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+
+#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT)
+
+#ifndef MIN
+#define MIN(a,b)	((a) < (b) ? (a) : (b))
+#endif
+
+/*
+ *    Define the Moxa PCI vendor and device IDs.
+ */
+
+#ifndef	PCI_VENDOR_ID_MOXA
+#define	PCI_VENDOR_ID_MOXA	0x1393
+#endif
+#ifndef PCI_DEVICE_ID_C168
+#define PCI_DEVICE_ID_C168	0x1680
+#endif
+#ifndef PCI_DEVICE_ID_C104
+#define PCI_DEVICE_ID_C104	0x1040
+#endif
+
+#define C168_ASIC_ID    1
+#define C104_ASIC_ID    2
+#define CI104J_ASIC_ID  5
+
+enum {
+	MXSER_BOARD_C168_ISA = 1,
+	MXSER_BOARD_C104_ISA,
+	MXSER_BOARD_CI104J,
+	MXSER_BOARD_C168_PCI,
+	MXSER_BOARD_C104_PCI,
+};
+
+static char *mxser_brdname[] =
+{
+	"C168 series",
+	"C104 series",
+	"CI-104J series",
+	"C168H/PCI series",
+	"C104H/PCI series",
+};
+
+static int mxser_numports[] =
+{
+	8,
+	4,
+	4,
+	8,
+	4,
+};
+
+/*
+ *    MOXA ioctls
+ */
+#define 	MOXA		0x400
+#define 	MOXA_GETDATACOUNT     (MOXA + 23)
+#define		MOXA_GET_CONF         (MOXA + 35)
+#define 	MOXA_DIAGNOSE         (MOXA + 50)
+#define 	MOXA_CHKPORTENABLE    (MOXA + 60)
+#define 	MOXA_HighSpeedOn      (MOXA + 61)
+#define         MOXA_GET_MAJOR        (MOXA + 63)
+#define         MOXA_GET_CUMAJOR      (MOXA + 64)
+#define         MOXA_GETMSTATUS       (MOXA + 65)
+
+typedef struct {
+	unsigned short vendor_id;
+	unsigned short device_id;
+	unsigned short board_type;
+} mxser_pciinfo;
+
+static mxser_pciinfo mxser_pcibrds[] =
+{
+	{PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_C168, MXSER_BOARD_C168_PCI},
+	{PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_C104, MXSER_BOARD_C104_PCI},
+};
+
+typedef struct _moxa_pci_info {
+	unsigned short busNum;
+	unsigned short devNum;
+} moxa_pci_info;
+
+static int ioaddr[MXSER_BOARDS] = {0, 0, 0, 0};
+static int ttymajor = MXSERMAJOR;
+static int calloutmajor = MXSERCUMAJOR;
+static int verbose = 0;
+
+#ifdef MODULE
+/* Variables for insmod */
+
+MODULE_AUTHOR("William Chen");
+MODULE_DESCRIPTION("MOXA Smartio Family Multiport Board Device Driver");
+MODULE_PARM(ioaddr, "1-4i");
+MODULE_PARM(ttymajor, "i");
+MODULE_PARM(calloutmajor, "i");
+MODULE_PARM(verbose, "i");
+
+#endif	/* MODULE */
+
+struct mxser_hwconf {
+	int board_type;
+	int ports;
+	int irq;
+	int vector;
+	int vector_mask;
+	int uart_type;
+	int ioaddr[MXSER_PORTS_PER_BOARD];
+	int baud_base[MXSER_PORTS_PER_BOARD];
+	moxa_pci_info pciInfo;
+};
+
+struct mxser_struct {
+	int port;
+	int base;		/* port base address */
+	int irq;		/* port using irq no. */
+	int vector;		/* port irq vector */
+	int vectormask;		/* port vector mask */
+	int rx_trigger;		/* Rx fifo trigger level */
+	int baud_base;		/* max. speed */
+	int flags;		/* defined in tty.h */
+	int type;		/* UART type */
+	struct tty_struct *tty;
+	int read_status_mask;
+	int ignore_status_mask;
+	int xmit_fifo_size;
+	int custom_divisor;
+	int x_char;		/* xon/xoff character */
+	int close_delay;
+	unsigned short closing_wait;
+	int IER;		/* Interrupt Enable Register */
+	int MCR;		/* Modem control register */
+	unsigned long event;
+	int count;		/* # of fd on device */
+	int blocked_open;	/* # of blocked opens */
+	long session;		/* Session of opening process */
+	long pgrp;		/* pgrp of opening process */
+	unsigned char *xmit_buf;
+	int xmit_head;
+	int xmit_tail;
+	int xmit_cnt;
+	struct tq_struct tqueue;
+	struct termios normal_termios;
+	struct termios callout_termios;
+	struct wait_queue *open_wait;
+	struct wait_queue *close_wait;
+	struct wait_queue *delta_msr_wait;
+	struct async_icount icount;	/* kernel counters for the 4 input interrupts */
+};
+
+struct mxser_log {
+	int tick;
+	int rxcnt[MXSER_PORTS];
+	int txcnt[MXSER_PORTS];
+};
+
+struct mxser_mstatus {
+	tcflag_t cflag;
+	int cts;
+	int dsr;
+	int ri;
+	int dcd;
+};
+
+static struct mxser_mstatus GMStatus[MXSER_PORTS];
+
+static int mxserBoardCAP[MXSER_BOARDS] =
+{
+	0, 0, 0, 0
+       /*  0x180, 0x280, 0x200, 0x320   */
+};
+
+
+static struct tty_driver mxvar_sdriver, mxvar_cdriver;
+static int mxvar_refcount;
+static struct mxser_struct mxvar_table[MXSER_PORTS];
+static struct tty_struct *mxvar_tty[MXSER_PORTS + 1];
+static struct termios *mxvar_termios[MXSER_PORTS + 1];
+static struct termios *mxvar_termios_locked[MXSER_PORTS + 1];
+static struct mxser_log mxvar_log;
+static int mxvar_diagflag;
+/*
+ * mxvar_tmp_buf is used as a temporary buffer by serial_write. We need
+ * to lock it in case the memcpy_fromfs blocks while swapping in a page,
+ * and some other program tries to do a serial write at the same time.
+ * Since the lock will only come under contention when the system is
+ * swapping and available memory is low, it makes sense to share one
+ * buffer across all the serial ports, since it significantly saves
+ * memory if large numbers of serial ports are open.
+ */
+static unsigned char *mxvar_tmp_buf = 0;
+static struct semaphore mxvar_tmp_buf_sem = MUTEX;
+
+/*
+ * This is used to figure out the divisor speeds and the timeouts
+ */
+static int mxvar_baud_table[] =
+{
+	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+	9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600, 0};
+
+struct mxser_hwconf mxsercfg[MXSER_BOARDS];
+
+/*
+ * static functions:
+ */
+
+#ifdef MODULE
+int init_module(void);
+void cleanup_module(void);
+#endif
+
+static void mxser_getcfg(int board, struct mxser_hwconf *hwconf);
+int mxser_init(void);
+static int mxser_get_ISA_conf(int, struct mxser_hwconf *);
+static int mxser_get_PCI_conf(int, int, int, struct mxser_hwconf *);
+static void mxser_do_softint(void *);
+static int mxser_open(struct tty_struct *, struct file *);
+static void mxser_close(struct tty_struct *, struct file *);
+static int mxser_write(struct tty_struct *, int, const unsigned char *, int);
+static int mxser_write_room(struct tty_struct *);
+static void mxser_flush_buffer(struct tty_struct *);
+static int mxser_chars_in_buffer(struct tty_struct *);
+static void mxser_flush_chars(struct tty_struct *);
+static void mxser_put_char(struct tty_struct *, unsigned char);
+static int mxser_ioctl(struct tty_struct *, struct file *, uint, ulong);
+static int mxser_ioctl_special(unsigned int, unsigned long);
+static void mxser_throttle(struct tty_struct *);
+static void mxser_unthrottle(struct tty_struct *);
+static void mxser_set_termios(struct tty_struct *, struct termios *);
+static void mxser_stop(struct tty_struct *);
+static void mxser_start(struct tty_struct *);
+static void mxser_hangup(struct tty_struct *);
+static void mxser_interrupt(int, void *, struct pt_regs *);
+static inline void mxser_receive_chars(struct mxser_struct *, int *);
+static inline void mxser_transmit_chars(struct mxser_struct *);
+static inline void mxser_check_modem_status(struct mxser_struct *, int);
+static int mxser_block_til_ready(struct tty_struct *, struct file *, struct mxser_struct *);
+static int mxser_startup(struct mxser_struct *);
+static void mxser_shutdown(struct mxser_struct *);
+static int mxser_change_speed(struct mxser_struct *, struct termios *old_termios);
+static int mxser_get_serial_info(struct mxser_struct *, struct serial_struct *);
+static int mxser_set_serial_info(struct mxser_struct *, struct serial_struct *);
+static int mxser_get_lsr_info(struct mxser_struct *, unsigned int *);
+static void mxser_send_break(struct mxser_struct *, int);
+static int mxser_get_modem_info(struct mxser_struct *, unsigned int *);
+static int mxser_set_modem_info(struct mxser_struct *, unsigned int, unsigned int *);
+
+/*
+ * The MOXA C168/C104 serial driver boot-time initialization code!
+ */
+
+
+#ifdef MODULE
+int init_module(void)
+{
+	int ret;
+
+	if (verbose)
+		printk("Loading module mxser ...\n");
+	ret = mxser_init();
+	if (verbose)
+		printk("Done.\n");
+	return (ret);
+}
+
+void cleanup_module(void)
+{
+	int i, err = 0;
+
+
+	if (verbose)
+		printk("Unloading module mxser ...\n");
+	if ((err |= tty_unregister_driver(&mxvar_cdriver)))
+		printk("Couldn't unregister MOXA Smartio family callout driver\n");
+	if ((err |= tty_unregister_driver(&mxvar_sdriver)))
+		printk("Couldn't unregister MOXA Smartio family serial driver\n");
+
+	for (i = 0; i < MXSER_BOARDS; i++) {
+		if (mxsercfg[i].board_type == -1)
+			continue;
+		else {
+			free_irq(mxsercfg[i].irq, &mxvar_table[i * MXSER_PORTS_PER_BOARD]);
+		}
+	}
+
+	if (verbose)
+		printk("Done.\n");
+
+}
+#endif
+
+
+int mxser_initbrd(int board, struct mxser_hwconf *hwconf)
+{
+	struct mxser_struct *info;
+	unsigned long flags;
+	int retval;
+	int i, n;
+
+	n = board * MXSER_PORTS_PER_BOARD;
+	info = &mxvar_table[n];
+	for (i = 0; i < hwconf->ports; i++, n++, info++) {
+		if (verbose) {
+			printk("        ttyM%d/cum%d at 0x%04x ", n, n, hwconf->ioaddr[i]);
+			if (hwconf->baud_base[i] == 115200)
+				printk(" max. baud rate up to 115200 bps.\n");
+			else
+				printk(" max. baud rate up to 921600 bps.\n");
+		}
+		info->port = n;
+		info->base = hwconf->ioaddr[i];
+		info->irq = hwconf->irq;
+		info->vector = hwconf->vector;
+		info->vectormask = hwconf->vector_mask;
+		info->rx_trigger = 14;
+		info->baud_base = hwconf->baud_base[i];
+		info->flags = ASYNC_SHARE_IRQ;
+		info->type = hwconf->uart_type;
+		if ((info->type == PORT_16450) || (info->type == PORT_8250))
+			info->xmit_fifo_size = 1;
+		else
+			info->xmit_fifo_size = 16;
+		info->custom_divisor = hwconf->baud_base[i] * 16;
+		info->close_delay = 5 * HZ / 10;
+		info->closing_wait = 30 * HZ;
+		info->tqueue.routine = mxser_do_softint;
+		info->tqueue.data = info;
+		info->callout_termios = mxvar_cdriver.init_termios;
+		info->normal_termios = mxvar_sdriver.init_termios;
+	}
+
+	/*
+	 * Allocate the IRQ if necessary
+	 */
+	save_flags(flags);
+
+	n = board * MXSER_PORTS_PER_BOARD;
+	info = &mxvar_table[n];
+
+	cli();
+	retval = request_irq(hwconf->irq, mxser_interrupt, IRQ_T(info),
+			     "mxser", info);
+	if (retval) {
+		restore_flags(flags);
+		printk("Board %d: %s", board, mxser_brdname[hwconf->board_type - 1]);
+		printk("  Request irq fail,IRQ (%d) may be conflit with another device.\n", info->irq);
+		return (retval);
+	}
+	restore_flags(flags);
+
+	return 0;
+}
+
+
+static void mxser_getcfg(int board, struct mxser_hwconf *hwconf)
+{
+	mxsercfg[board] = *hwconf;
+}
+
+static int mxser_get_PCI_conf(int busnum, int devnum, int board_type, struct mxser_hwconf *hwconf)
+{
+	int i;
+	unsigned int val, ioaddress;
+
+	hwconf->board_type = board_type;
+	hwconf->ports = mxser_numports[board_type - 1];
+	pcibios_read_config_dword(busnum, devnum, PCI_BASE_ADDRESS_2, &val);
+	if (val == 0xffffffff)
+		return (MXSER_ERR_IOADDR);
+	else
+		ioaddress = val & 0xffffffc;
+	for (i = 0; i < hwconf->ports; i++)
+		hwconf->ioaddr[i] = ioaddress + 8 * i;
+
+	pcibios_read_config_dword(busnum, devnum, PCI_BASE_ADDRESS_3, &val);
+	if (val == 0xffffffff)
+		return (MXSER_ERR_VECTOR);
+	else
+		ioaddress = val & 0xffffffc;
+	hwconf->vector = ioaddress;
+
+	pcibios_read_config_dword(busnum, devnum, PCI_INTERRUPT_LINE, &val);
+	if (val == 0xffffffff)
+		return (MXSER_ERR_IRQ);
+	else
+		hwconf->irq = val & 0xff;
+
+	hwconf->uart_type = PORT_16550A;
+	hwconf->vector_mask = 0;
+	for (i = 0; i < hwconf->ports; i++) {
+		hwconf->vector_mask |= (1 << i);
+		hwconf->baud_base[i] = 921600;
+	}
+	return (0);
+}
+
+int mxser_init(void)
+{
+	int i, m, retval, b;
+	int n, index;
+	int ret1, ret2;
+	unsigned char busnum, devnum;
+	struct mxser_hwconf hwconf;
+
+	printk("MOXA Smartio family driver version %s\n", MXSER_VERSION);
+
+	/* Initialize the tty_driver structure */
+
+	memset(&mxvar_sdriver, 0, sizeof(struct tty_driver));
+	mxvar_sdriver.magic = TTY_DRIVER_MAGIC;
+	mxvar_sdriver.name = "ttyM";
+	mxvar_sdriver.major = ttymajor;
+	mxvar_sdriver.minor_start = 0;
+	mxvar_sdriver.num = MXSER_PORTS + 1;
+	mxvar_sdriver.type = TTY_DRIVER_TYPE_SERIAL;
+	mxvar_sdriver.subtype = SERIAL_TYPE_NORMAL;
+	mxvar_sdriver.init_termios = tty_std_termios;
+	mxvar_sdriver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	mxvar_sdriver.flags = TTY_DRIVER_REAL_RAW;
+	mxvar_sdriver.refcount = &mxvar_refcount;
+	mxvar_sdriver.table = mxvar_tty;
+	mxvar_sdriver.termios = mxvar_termios;
+	mxvar_sdriver.termios_locked = mxvar_termios_locked;
+
+	mxvar_sdriver.open = mxser_open;
+	mxvar_sdriver.close = mxser_close;
+	mxvar_sdriver.write = mxser_write;
+	mxvar_sdriver.put_char = mxser_put_char;
+	mxvar_sdriver.flush_chars = mxser_flush_chars;
+	mxvar_sdriver.write_room = mxser_write_room;
+	mxvar_sdriver.chars_in_buffer = mxser_chars_in_buffer;
+	mxvar_sdriver.flush_buffer = mxser_flush_buffer;
+	mxvar_sdriver.ioctl = mxser_ioctl;
+	mxvar_sdriver.throttle = mxser_throttle;
+	mxvar_sdriver.unthrottle = mxser_unthrottle;
+	mxvar_sdriver.set_termios = mxser_set_termios;
+	mxvar_sdriver.stop = mxser_stop;
+	mxvar_sdriver.start = mxser_start;
+	mxvar_sdriver.hangup = mxser_hangup;
+
+	/*
+	 * The callout device is just like normal device except for
+	 * major number and the subtype code.
+	 */
+	mxvar_cdriver = mxvar_sdriver;
+	mxvar_cdriver.name = "cum";
+	mxvar_cdriver.major = calloutmajor;
+	mxvar_cdriver.subtype = SERIAL_TYPE_CALLOUT;
+
+	printk("Tty devices major number = %d, callout devices major number = %d\n", ttymajor, calloutmajor);
+
+	mxvar_diagflag = 0;
+	memset(mxvar_table, 0, MXSER_PORTS * sizeof(struct mxser_struct));
+	memset(&mxvar_log, 0, sizeof(struct mxser_log));
+
+
+	m = 0;
+	/* Start finding ISA boards here */
+	for (b = 0; b < MXSER_BOARDS && m < MXSER_BOARDS; b++) {
+		int cap;
+		if (!(cap = mxserBoardCAP[b]))
+			continue;
+
+		retval = mxser_get_ISA_conf(cap, &hwconf);
+
+		if (retval != 0)
+			printk("Found MOXA %s board (CAP=0x%x)\n",
+			       mxser_brdname[hwconf.board_type - 1],
+			       ioaddr[b]);
+
+		if (retval <= 0) {
+			if (retval == MXSER_ERR_IRQ)
+				printk("Invalid interrupt number,board not configured\n");
+			else if (retval == MXSER_ERR_IRQ_CONFLIT)
+				printk("Invalid interrupt number,board not configured\n");
+			else if (retval == MXSER_ERR_VECTOR)
+				printk("Invalid interrupt vector,board not configured\n");
+			else if (retval == MXSER_ERR_IOADDR)
+				printk("Invalid I/O address,board not configured\n");
+
+			continue;
+		}
+		hwconf.pciInfo.busNum = 0;
+		hwconf.pciInfo.devNum = 0;
+
+		if (mxser_initbrd(m, &hwconf) < 0)
+			continue;
+
+		mxser_getcfg(m, &hwconf);
+
+		m++;
+	}
+
+	/* Start finding ISA boards from module arg */
+	for (b = 0; b < MXSER_BOARDS && m < MXSER_BOARDS; b++) {
+		int cap;
+		if (!(cap = ioaddr[b]))
+			continue;
+
+		retval = mxser_get_ISA_conf(cap, &hwconf);
+
+		if (retval != 0)
+			printk("Found MOXA %s board (CAP=0x%x)\n",
+			       mxser_brdname[hwconf.board_type - 1],
+			       ioaddr[b]);
+
+		if (retval <= 0) {
+			if (retval == MXSER_ERR_IRQ)
+				printk("Invalid interrupt number,board not configured\n");
+			else if (retval == MXSER_ERR_IRQ_CONFLIT)
+				printk("Invalid interrupt number,board not configured\n");
+			else if (retval == MXSER_ERR_VECTOR)
+				printk("Invalid interrupt vector,board not configured\n");
+			else if (retval == MXSER_ERR_IOADDR)
+				printk("Invalid I/O address,board not configured\n");
+
+			continue;
+		}
+		hwconf.pciInfo.busNum = 0;
+		hwconf.pciInfo.devNum = 0;
+
+		if (mxser_initbrd(m, &hwconf) < 0)
+			continue;
+
+		mxser_getcfg(m, &hwconf);
+
+		m++;
+	}
+
+	/* start finding PCI board here */
+
+#ifdef CONFIG_PCI
+	if (pci_present()) 
+	{
+		n = sizeof(mxser_pcibrds) / sizeof(mxser_pciinfo);
+		index = 0;
+		b = 0;
+		while (b < n) {
+			if (pcibios_find_device(mxser_pcibrds[b].vendor_id,
+					      mxser_pcibrds[b].device_id,
+						index,
+						&busnum,
+						&devnum) != 0) {
+				b++;
+				index = 0;
+				continue;
+			}
+			hwconf.pciInfo.busNum = busnum;
+			hwconf.pciInfo.devNum = devnum;
+			printk("Found MOXA %s board(BusNo=%d,DevNo=%d)\n", mxser_brdname[mxser_pcibrds[b].board_type - 1], busnum, devnum >> 3);
+			index++;
+			if (m >= MXSER_BOARDS) {
+				printk("Too many Smartio family boards find (maximum %d),board not configured\n", MXSER_BOARDS);
+			} else {
+				retval = mxser_get_PCI_conf(busnum, devnum,
+				   mxser_pcibrds[b].board_type, &hwconf);
+				if (retval < 0) {
+					if (retval == MXSER_ERR_IRQ)
+						printk("Invalid interrupt number,board not configured\n");
+					else if (retval == MXSER_ERR_IRQ_CONFLIT)
+						printk("Invalid interrupt number,board not configured\n");
+					else if (retval == MXSER_ERR_VECTOR)
+						printk("Invalid interrupt vector,board not configured\n");
+					else if (retval == MXSER_ERR_IOADDR)
+						printk("Invalid I/O address,board not configured\n");
+					continue;
+
+				}
+				if (mxser_initbrd(m, &hwconf) < 0)
+					continue;
+				mxser_getcfg(m, &hwconf);
+				m++;
+
+			}
+
+		}
+	}
+#endif
+
+	for (i = m; i < MXSER_BOARDS; i++) {
+		mxsercfg[i].board_type = -1;
+	}
+
+
+	ret1 = 0;
+	ret2 = 0;
+	if (!(ret1 = tty_register_driver(&mxvar_sdriver))) {
+		if (!(ret2 = tty_register_driver(&mxvar_cdriver))) {
+			return 0;
+		} else {
+			tty_unregister_driver(&mxvar_sdriver);
+			printk("Couldn't install MOXA Smartio family callout driver !\n");
+		}
+	} else
+		printk("Couldn't install MOXA Smartio family driver !\n");
+
+
+	if (ret1 || ret2) {
+		for (i = 0; i < MXSER_BOARDS; i++) {
+			if (mxsercfg[i].board_type == -1)
+				continue;
+			else {
+				free_irq(mxsercfg[i].irq, &mxvar_table[i * MXSER_PORTS_PER_BOARD]);
+			}
+		}
+		return -1;
+	}
+	return (0);
+}
+
+static void mxser_do_softint(void *private_)
+{
+	struct mxser_struct *info = (struct mxser_struct *) private_;
+	struct tty_struct *tty;
+
+	tty = info->tty;
+	if (!tty)
+		return;
+	if (test_and_clear_bit(MXSER_EVENT_TXLOW, &info->event)) {
+		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+		    tty->ldisc.write_wakeup)
+			(tty->ldisc.write_wakeup) (tty);
+		wake_up_interruptible(&tty->write_wait);
+	}
+	if (test_and_clear_bit(MXSER_EVENT_HANGUP, &info->event)) {
+		tty_hangup(tty);
+	}
+}
+
+/*
+ * This routine is called whenever a serial port is opened.  It
+ * enables interrupts for a serial port, linking in its async structure into
+ * the IRQ chain.   It also performs the serial-specific
+ * initialization for the tty structure.
+ */
+
+static int mxser_open(struct tty_struct *tty, struct file *filp)
+{
+	struct mxser_struct *info;
+	int retval, line;
+	unsigned long page;
+
+	line = PORTNO(tty);
+	if (line == MXSER_PORTS)
+		return (0);
+	if ((line < 0) || (line > MXSER_PORTS))
+		return (-ENODEV);
+	info = mxvar_table + line;
+	if (!info->base)
+		return (-ENODEV);
+
+	info->count++;
+	tty->driver_data = info;
+	info->tty = tty;
+
+	if (!mxvar_tmp_buf) {
+		page = get_free_page(GFP_KERNEL);
+		if (!page)
+			return (-ENOMEM);
+		if (mxvar_tmp_buf)
+			free_page(page);
+		else
+			mxvar_tmp_buf = (unsigned char *) page;
+	}
+	/*
+	 * Start up serial port
+	 */
+	retval = mxser_startup(info);
+	if (retval)
+		return (retval);
+
+	retval = mxser_block_til_ready(tty, filp, info);
+	if (retval)
+		return (retval);
+
+	if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
+		if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+			*tty->termios = info->normal_termios;
+		else
+			*tty->termios = info->callout_termios;
+		mxser_change_speed(info, 0);
+	}
+	info->session = current->session;
+	info->pgrp = current->pgrp;
+
+	MOD_INC_USE_COUNT;
+
+	return (0);
+}
+
+/*
+ * This routine is called when the serial port gets closed.  First, we
+ * wait for the last remaining data to be sent.  Then, we unlink its
+ * async structure from the interrupt chain if necessary, and we free
+ * that IRQ if nothing is left in the chain.
+ */
+
+static void mxser_close(struct tty_struct *tty, struct file *filp)
+{
+	struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+	unsigned long flags;
+	unsigned long timeout;
+
+	if (PORTNO(tty) == MXSER_PORTS)
+		return;
+	if (!info)
+		return;
+
+	save_flags(flags);
+	cli();
+
+	if (tty_hung_up_p(filp)) {
+		restore_flags(flags);
+		MOD_DEC_USE_COUNT;
+		return;
+	}
+	if ((tty->count == 1) && (info->count != 1)) {
+		/*
+		 * Uh, oh.        tty->count is 1, which means that the tty
+		 * structure will be freed.  Info->count should always
+		 * be one in these conditions.  If it's greater than
+		 * one, we've got real problems, since it means the
+		 * serial port won't be shutdown.
+		 */
+		printk("mxser_close: bad serial port count; tty->count is 1, "
+		       "info->count is %d\n", info->count);
+		info->count = 1;
+	}
+	if (--info->count < 0) {
+		printk("mxser_close: bad serial port count for ttys%d: %d\n",
+		       info->port, info->count);
+		info->count = 0;
+	}
+	if (info->count) {
+		restore_flags(flags);
+		MOD_DEC_USE_COUNT;
+		return;
+	}
+	info->flags |= ASYNC_CLOSING;
+	/*
+	 * Save the termios structure, since this port may have
+	 * separate termios for callout and dialin.
+	 */
+	if (info->flags & ASYNC_NORMAL_ACTIVE)
+		info->normal_termios = *tty->termios;
+	if (info->flags & ASYNC_CALLOUT_ACTIVE)
+		info->callout_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->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+		tty_wait_until_sent(tty, info->closing_wait);
+	/*
+	 * At this point we stop accepting input.  To do this, we
+	 * disable the receive line status interrupts, and tell the
+	 * interrupt driver to stop checking the data ready bit in the
+	 * line status register.
+	 */
+	info->IER &= ~UART_IER_RLSI;
+	/* by William
+	   info->read_status_mask &= ~UART_LSR_DR;
+	 */
+	if (info->flags & ASYNC_INITIALIZED) {
+		outb(info->IER, info->base + UART_IER);
+		/*
+		 * Before we drop DTR, make sure the UART transmitter
+		 * has completely drained; this is especially
+		 * important if there is a transmit FIFO!
+		 */
+		timeout = jiffies + HZ;
+		while (!(inb(info->base + UART_LSR) & UART_LSR_TEMT)) {
+			current->state = TASK_INTERRUPTIBLE;
+			schedule_timeout(5);
+			if (jiffies > timeout)
+				break;
+		}
+	}
+	mxser_shutdown(info);
+	if (tty->driver.flush_buffer)
+		tty->driver.flush_buffer(tty);
+	if (tty->ldisc.flush_buffer)
+		tty->ldisc.flush_buffer(tty);
+	tty->closing = 0;
+	info->event = 0;
+	info->tty = 0;
+	if (info->blocked_open) {
+		if (info->close_delay) {
+			current->state = TASK_INTERRUPTIBLE;
+			schedule_timeout(info->close_delay);
+		}
+		wake_up_interruptible(&info->open_wait);
+	}
+	info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE |
+			 ASYNC_CLOSING);
+	wake_up_interruptible(&info->close_wait);
+	restore_flags(flags);
+
+	MOD_DEC_USE_COUNT;
+}
+
+static int mxser_write(struct tty_struct *tty, int from_user,
+		       const unsigned char *buf, int count)
+{
+	int c, total = 0;
+	struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+	unsigned long flags;
+
+	if (!tty || !info->xmit_buf || !mxvar_tmp_buf)
+		return (0);
+
+	if (from_user)
+		down(&mxvar_tmp_buf_sem);
+	save_flags(flags);
+	while (1) {
+		cli();
+		c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+				   SERIAL_XMIT_SIZE - info->xmit_head));
+		if (c <= 0)
+			break;
+
+		if (from_user) {
+			copy_from_user(mxvar_tmp_buf, buf, c);
+			c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+				    SERIAL_XMIT_SIZE - info->xmit_head));
+			memcpy(info->xmit_buf + info->xmit_head, mxvar_tmp_buf, c);
+		} else
+			memcpy(info->xmit_buf + info->xmit_head, buf, c);
+		info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE - 1);
+		info->xmit_cnt += c;
+		restore_flags(flags);
+		buf += c;
+		count -= c;
+		total += c;
+	}
+	if (from_user)
+		up(&mxvar_tmp_buf_sem);
+	if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped &&
+	    !(info->IER & UART_IER_THRI)) {
+		info->IER |= UART_IER_THRI;
+		outb(info->IER, info->base + UART_IER);
+	}
+	restore_flags(flags);
+	return (total);
+}
+
+static void mxser_put_char(struct tty_struct *tty, unsigned char ch)
+{
+	struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+	unsigned long flags;
+
+	if (!tty || !info->xmit_buf)
+		return;
+
+	save_flags(flags);
+	cli();
+	if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
+		restore_flags(flags);
+		return;
+	}
+	info->xmit_buf[info->xmit_head++] = ch;
+	info->xmit_head &= SERIAL_XMIT_SIZE - 1;
+	info->xmit_cnt++;
+	/********************************************** why ??? ***********
+	if ( !tty->stopped && !tty->hw_stopped &&
+	     !(info->IER & UART_IER_THRI) ) {
+	    info->IER |= UART_IER_THRI;
+	    outb(info->IER, info->base + UART_IER);
+	}
+	*****************************************************************/
+	restore_flags(flags);
+}
+
+static void mxser_flush_chars(struct tty_struct *tty)
+{
+	struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+	unsigned long flags;
+
+	if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
+	    !info->xmit_buf)
+		return;
+
+	save_flags(flags);
+	cli();
+	info->IER |= UART_IER_THRI;
+	outb(info->IER, info->base + UART_IER);
+	restore_flags(flags);
+}
+
+static int mxser_write_room(struct tty_struct *tty)
+{
+	struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+	int ret;
+
+	ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
+	if (ret < 0)
+		ret = 0;
+	return (ret);
+}
+
+static int mxser_chars_in_buffer(struct tty_struct *tty)
+{
+	struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+
+	return (info->xmit_cnt);
+}
+
+static void mxser_flush_buffer(struct tty_struct *tty)
+{
+	struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+	restore_flags(flags);
+	wake_up_interruptible(&tty->write_wait);
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+	    tty->ldisc.write_wakeup)
+		(tty->ldisc.write_wakeup) (tty);
+}
+
+static int mxser_ioctl(struct tty_struct *tty, struct file *file,
+		       unsigned int cmd, unsigned long arg)
+{
+	unsigned long flags;
+	struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+	int retval;
+	struct async_icount cprev, cnow;	/* kernel counter temps */
+	struct serial_icounter_struct *p_cuser;		/* user space */
+	unsigned long templ;
+
+	if (PORTNO(tty) == MXSER_PORTS)
+		return (mxser_ioctl_special(cmd, arg));
+	if ((cmd != TIOCGSERIAL) && (cmd != TIOCMIWAIT) &&
+	    (cmd != TIOCGICOUNT)) {
+		if (tty->flags & (1 << TTY_IO_ERROR))
+			return (-EIO);
+	}
+	switch (cmd) {
+	case TCSBRK:		/* SVID version: non-zero arg --> no break */
+		retval = tty_check_change(tty);
+		if (retval)
+			return (retval);
+		tty_wait_until_sent(tty, 0);
+		if (!arg)
+			mxser_send_break(info, HZ / 4);		/* 1/4 second */
+		return (0);
+	case TCSBRKP:		/* support for POSIX tcsendbreak() */
+		retval = tty_check_change(tty);
+		if (retval)
+			return (retval);
+		tty_wait_until_sent(tty, 0);
+		mxser_send_break(info, arg ? arg * (HZ / 10) : HZ / 4);
+		return (0);
+	case TIOCGSOFTCAR:
+		return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg);
+	case TIOCSSOFTCAR:
+		if(get_user(templ, (unsigned long *) arg))
+			return -EFAULT;
+		arg = templ;
+		tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) |
+					 (arg ? CLOCAL : 0));
+		return (0);
+	case TIOCMGET:
+		return (mxser_get_modem_info(info, (unsigned int *) arg));
+	case TIOCMBIS:
+	case TIOCMBIC:
+	case TIOCMSET:
+		return (mxser_set_modem_info(info, cmd, (unsigned int *) arg));
+	case TIOCGSERIAL:
+		return (mxser_get_serial_info(info, (struct serial_struct *) arg));
+	case TIOCSSERIAL:
+		return (mxser_set_serial_info(info, (struct serial_struct *) arg));
+	case TIOCSERGETLSR:	/* Get line status register */
+		return (mxser_get_lsr_info(info, (unsigned int *) arg));
+		/*
+		 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
+		 * - mask passed in arg for lines of interest
+		 *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
+		 * Caller should use TIOCGICOUNT to see which one it was
+		 */
+	case TIOCMIWAIT:
+		save_flags(flags);
+		cli();
+		cprev = info->icount;	/* note the counters on entry */
+		restore_flags(flags);
+		while (1) {
+			interruptible_sleep_on(&info->delta_msr_wait);
+			/* see if a signal did it */
+			if (signal_pending(current))
+				return (-ERESTARTSYS);
+			save_flags(flags);
+			cli();
+			cnow = info->icount;	/* atomic copy */
+			restore_flags(flags);
+			if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
+			  cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
+				return (-EIO);	/* no change => error */
+			if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
+			((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
+			 ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
+			((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
+				return (0);
+			}
+			cprev = cnow;
+		}
+		/* NOTREACHED */
+		/*
+		 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
+		 * Return: write counters to the user passed counter struct
+		 * NB: both 1->0 and 0->1 transitions are counted except for
+		 *     RI where only 0->1 is counted.
+		 */
+	case TIOCGICOUNT:
+		save_flags(flags);
+		cli();
+		cnow = info->icount;
+		restore_flags(flags);
+		p_cuser = (struct serial_icounter_struct *) arg;
+		if(put_user(cnow.cts, &p_cuser->cts))
+			return -EFAULT;
+		if(put_user(cnow.dsr, &p_cuser->dsr))
+			return -EFAULT;
+		if(put_user(cnow.rng, &p_cuser->rng))
+			return -EFAULT;
+		return put_user(cnow.dcd, &p_cuser->dcd);
+	case MOXA_HighSpeedOn:
+		return put_user(info->baud_base != 115200 ? 1 : 0, (int *) arg);
+	default:
+		return (-ENOIOCTLCMD);
+	}
+	return (0);
+}
+
+static int mxser_ioctl_special(unsigned int cmd, unsigned long arg)
+{
+	int i, result, status;
+
+	switch (cmd) {
+	case MOXA_GET_CONF:
+		if(copy_to_user((struct mxser_hwconf *) arg, mxsercfg,
+			     sizeof(struct mxser_hwconf) * 4))
+			     	return -EFAULT;
+		return 0;
+	case MOXA_GET_MAJOR:
+		if(copy_to_user((int *) arg, &ttymajor, sizeof(int)))
+			return -EFAULT;
+		return 0;
+
+	case MOXA_GET_CUMAJOR:
+		if(copy_to_user((int *) arg, &calloutmajor, sizeof(int)))
+			return -EFAULT;
+		return 0;
+
+	case MOXA_CHKPORTENABLE:
+		result = 0;
+		for (i = 0; i < MXSER_PORTS; i++) {
+			if (mxvar_table[i].base)
+				result |= (1 << i);
+		}
+		return put_user(result, (unsigned long *) arg);
+	case MOXA_GETDATACOUNT:
+		if(copy_to_user((struct mxser_log *) arg, &mxvar_log, sizeof(mxvar_log)))
+			return -EFAULT;
+		return (0);
+	case MOXA_GETMSTATUS:
+		for (i = 0; i < MXSER_PORTS; i++) {
+			GMStatus[i].ri = 0;
+			if (!mxvar_table[i].base) {
+				GMStatus[i].dcd = 0;
+				GMStatus[i].dsr = 0;
+				GMStatus[i].cts = 0;
+				continue;
+			}
+			if (!mxvar_table[i].tty || !mxvar_table[i].tty->termios)
+				GMStatus[i].cflag = mxvar_table[i].normal_termios.c_cflag;
+			else
+				GMStatus[i].cflag = mxvar_table[i].tty->termios->c_cflag;
+
+			status = inb(mxvar_table[i].base + UART_MSR);
+			if (status & 0x80 /*UART_MSR_DCD */ )
+				GMStatus[i].dcd = 1;
+			else
+				GMStatus[i].dcd = 0;
+
+			if (status & 0x20 /*UART_MSR_DSR */ )
+				GMStatus[i].dsr = 1;
+			else
+				GMStatus[i].dsr = 0;
+
+
+			if (status & 0x10 /*UART_MSR_CTS */ )
+				GMStatus[i].cts = 1;
+			else
+				GMStatus[i].cts = 0;
+		}
+		if(copy_to_user((struct mxser_mstatus *) arg, GMStatus,
+			     sizeof(struct mxser_mstatus) * MXSER_PORTS))
+			return -EFAULT;
+		return 0;
+	default:
+		return (-ENOIOCTLCMD);
+	}
+	return (0);
+}
+
+/*
+ * This routine is called by the upper-layer tty layer to signal that
+ * incoming characters should be throttled.
+ */
+static void mxser_throttle(struct tty_struct *tty)
+{
+	struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+	unsigned long flags;
+
+	if (I_IXOFF(tty)) {
+		info->x_char = STOP_CHAR(tty);
+		save_flags(flags);
+		cli();
+		outb(info->IER, 0);
+		info->IER |= UART_IER_THRI;
+		outb(info->IER, info->base + UART_IER);		/* force Tx interrupt */
+		restore_flags(flags);
+	}
+	if (info->tty->termios->c_cflag & CRTSCTS) {
+		info->MCR &= ~UART_MCR_RTS;
+		save_flags(flags);
+		cli();
+		outb(info->MCR, info->base + UART_MCR);
+		restore_flags(flags);
+	}
+}
+
+static void mxser_unthrottle(struct tty_struct *tty)
+{
+	struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+	unsigned long flags;
+
+	if (I_IXOFF(tty)) {
+		if (info->x_char)
+			info->x_char = 0;
+		else {
+			info->x_char = START_CHAR(tty);
+			save_flags(flags);
+			cli();
+			outb(info->IER, 0);
+			info->IER |= UART_IER_THRI;	/* force Tx interrupt */
+			outb(info->IER, info->base + UART_IER);
+			restore_flags(flags);
+		}
+	}
+	if (info->tty->termios->c_cflag & CRTSCTS) {
+		info->MCR |= UART_MCR_RTS;
+		save_flags(flags);
+		cli();
+		outb(info->MCR, info->base + UART_MCR);
+		restore_flags(flags);
+	}
+}
+
+static void mxser_set_termios(struct tty_struct *tty,
+			      struct termios *old_termios)
+{
+	struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+
+/* 8-2-99 by William
+   if ( (tty->termios->c_cflag == old_termios->c_cflag) &&
+   (RELEVANT_IFLAG(tty->termios->c_iflag) ==
+   RELEVANT_IFLAG(old_termios->c_iflag)) )
+   return;
+
+   mxser_change_speed(info, old_termios);
+
+   if ( (old_termios->c_cflag & CRTSCTS) &&
+   !(tty->termios->c_cflag & CRTSCTS) ) {
+   tty->hw_stopped = 0;
+   mxser_start(tty);
+   }
+ */
+	if ((tty->termios->c_cflag != old_termios->c_cflag) ||
+	    (RELEVANT_IFLAG(tty->termios->c_iflag) !=
+	     RELEVANT_IFLAG(old_termios->c_iflag))) {
+
+		mxser_change_speed(info, old_termios);
+
+		if ((old_termios->c_cflag & CRTSCTS) &&
+		    !(tty->termios->c_cflag & CRTSCTS)) {
+			tty->hw_stopped = 0;
+			mxser_start(tty);
+		}
+	}
+/* Handle sw stopped */
+	if ((old_termios->c_iflag & IXON) &&
+	    !(tty->termios->c_iflag & IXON)) {
+		tty->stopped = 0;
+		mxser_start(tty);
+	}
+}
+
+/*
+ * mxser_stop() and mxser_start()
+ *
+ * This routines are called before setting or resetting tty->stopped.
+ * They enable or disable transmitter interrupts, as necessary.
+ */
+static void mxser_stop(struct tty_struct *tty)
+{
+	struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	if (info->IER & UART_IER_THRI) {
+		info->IER &= ~UART_IER_THRI;
+		outb(info->IER, info->base + UART_IER);
+	}
+	restore_flags(flags);
+}
+
+static void mxser_start(struct tty_struct *tty)
+{
+	struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	if (info->xmit_cnt && info->xmit_buf &&
+	    !(info->IER & UART_IER_THRI)) {
+		info->IER |= UART_IER_THRI;
+		outb(info->IER, info->base + UART_IER);
+	}
+	restore_flags(flags);
+}
+
+/*
+ * This routine is called by tty_hangup() when a hangup is signaled.
+ */
+void mxser_hangup(struct tty_struct *tty)
+{
+	struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+
+	mxser_flush_buffer(tty);
+	mxser_shutdown(info);
+	info->event = 0;
+	info->count = 0;
+	info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE);
+	info->tty = 0;
+	wake_up_interruptible(&info->open_wait);
+}
+
+/*
+ * This is the serial driver's generic interrupt routine
+ */
+static void mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	int status, i;
+	struct mxser_struct *info;
+	struct mxser_struct *port;
+	int max, irqbits, bits, msr;
+	int pass_counter = 0;
+
+	port = 0;
+	for (i = 0; i < MXSER_BOARDS; i++) {
+		if (dev_id == &(mxvar_table[i * MXSER_PORTS_PER_BOARD])) {
+			port = dev_id;
+			break;
+		}
+	}
+
+	if (i == MXSER_BOARDS)
+		return;
+	if (port == 0)
+		return;
+	max = mxser_numports[mxsercfg[i].board_type - 1];
+
+	while (1) {
+		irqbits = inb(port->vector) & port->vectormask;
+		if (irqbits == port->vectormask)
+			break;
+		for (i = 0, bits = 1; i < max; i++, irqbits |= bits, bits <<= 1) {
+			if (irqbits == port->vectormask)
+				break;
+			if (bits & irqbits)
+				continue;
+			info = port + i;
+			if (!info->tty ||
+			  (inb(info->base + UART_IIR) & UART_IIR_NO_INT))
+				continue;
+			status = inb(info->base + UART_LSR) & info->read_status_mask;
+			if (status & UART_LSR_DR)
+				mxser_receive_chars(info, &status);
+			msr = inb(info->base + UART_MSR);
+			if (msr & UART_MSR_ANY_DELTA)
+				mxser_check_modem_status(info, msr);
+			if (status & UART_LSR_THRE) {
+/* 8-2-99 by William
+   if ( info->x_char || (info->xmit_cnt > 0) )
+ */
+				mxser_transmit_chars(info);
+			}
+		}
+		if (pass_counter++ > MXSER_ISR_PASS_LIMIT) {
+#if 0
+			printk("MOXA Smartio/Indusrtio family driver interrupt loop break\n");
+#endif
+			break;	/* Prevent infinite loops */
+		}
+	}
+}
+
+static inline void mxser_receive_chars(struct mxser_struct *info,
+					 int *status)
+{
+	struct tty_struct *tty = info->tty;
+	unsigned char ch;
+	int ignored = 0;
+	int cnt = 0;
+
+	do {
+		ch = inb(info->base + UART_RX);
+		if (*status & info->ignore_status_mask) {
+			if (++ignored > 100)
+				break;
+		} else {
+			if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+				break;
+			tty->flip.count++;
+			if (*status & UART_LSR_SPECIAL) {
+				if (*status & UART_LSR_BI) {
+					*tty->flip.flag_buf_ptr++ = TTY_BREAK;
+					if (info->flags & ASYNC_SAK)
+						do_SAK(tty);
+				} else if (*status & UART_LSR_PE) {
+					*tty->flip.flag_buf_ptr++ = TTY_PARITY;
+				} else if (*status & UART_LSR_FE) {
+					*tty->flip.flag_buf_ptr++ = TTY_FRAME;
+				} else if (*status & UART_LSR_OE) {
+					*tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
+				} else
+					*tty->flip.flag_buf_ptr++ = 0;
+			} else
+				*tty->flip.flag_buf_ptr++ = 0;
+			*tty->flip.char_buf_ptr++ = ch;
+			cnt++;
+		}
+		*status = inb(info->base + UART_LSR) & info->read_status_mask;
+	} while (*status & UART_LSR_DR);
+	mxvar_log.rxcnt[info->port] += cnt;
+	queue_task(&tty->flip.tqueue, &tq_timer);
+
+}
+
+static inline void mxser_transmit_chars(struct mxser_struct *info)
+{
+	int count, cnt;
+
+	if (info->x_char) {
+		outb(info->x_char, info->base + UART_TX);
+		info->x_char = 0;
+		mxvar_log.txcnt[info->port]++;
+		return;
+	}
+	if ((info->xmit_cnt <= 0) || info->tty->stopped ||
+	    info->tty->hw_stopped) {
+		info->IER &= ~UART_IER_THRI;
+		outb(info->IER, info->base + UART_IER);
+		return;
+	}
+	cnt = info->xmit_cnt;
+	count = info->xmit_fifo_size;
+	do {
+		outb(info->xmit_buf[info->xmit_tail++], info->base + UART_TX);
+		info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE - 1);
+		if (--info->xmit_cnt <= 0)
+			break;
+	} while (--count > 0);
+	mxvar_log.txcnt[info->port] += (cnt - info->xmit_cnt);
+
+	if (info->xmit_cnt < WAKEUP_CHARS) {
+		set_bit(MXSER_EVENT_TXLOW, &info->event);
+		queue_task(&info->tqueue, &tq_scheduler);
+	}
+	if (info->xmit_cnt <= 0) {
+		info->IER &= ~UART_IER_THRI;
+		outb(info->IER, info->base + UART_IER);
+	}
+}
+
+static inline void mxser_check_modem_status(struct mxser_struct *info,
+					      int status)
+{
+
+	/* update input line counters */
+	if (status & UART_MSR_TERI)
+		info->icount.rng++;
+	if (status & UART_MSR_DDSR)
+		info->icount.dsr++;
+	if (status & UART_MSR_DDCD)
+		info->icount.dcd++;
+	if (status & UART_MSR_DCTS)
+		info->icount.cts++;
+	wake_up_interruptible(&info->delta_msr_wait);
+
+	if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
+		if (status & UART_MSR_DCD)
+			wake_up_interruptible(&info->open_wait);
+		else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+			   (info->flags & ASYNC_CALLOUT_NOHUP)))
+			set_bit(MXSER_EVENT_HANGUP, &info->event);
+		queue_task(&info->tqueue, &tq_scheduler);
+
+	}
+	if (info->flags & ASYNC_CTS_FLOW) {
+		if (info->tty->hw_stopped) {
+			if (status & UART_MSR_CTS) {
+				info->tty->hw_stopped = 0;
+				info->IER |= UART_IER_THRI;
+				outb(info->IER, info->base + UART_IER);
+
+				set_bit(MXSER_EVENT_TXLOW, &info->event);
+				queue_task(&info->tqueue, &tq_scheduler);
+			}
+		} else {
+			if (!(status & UART_MSR_CTS)) {
+				info->tty->hw_stopped = 1;
+				info->IER &= ~UART_IER_THRI;
+				outb(info->IER, info->base + UART_IER);
+			}
+		}
+	}
+}
+
+static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp,
+				 struct mxser_struct *info)
+{
+	struct wait_queue wait = {current, NULL};
+	unsigned long flags;
+	int retval;
+	int do_clocal = 0;
+
+	/*
+	 * 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->flags & ASYNC_CLOSING)) {
+		if (info->flags & ASYNC_CLOSING)
+			interruptible_sleep_on(&info->close_wait);
+#ifdef SERIAL_DO_RESTART
+		if (info->flags & ASYNC_HUP_NOTIFY)
+			return (-EAGAIN);
+		else
+			return (-ERESTARTSYS);
+#else
+		return (-EAGAIN);
+#endif
+	}
+	/*
+	 * If this is a callout device, then just make sure the normal
+	 * device isn't being used.
+	 */
+	if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
+		if (info->flags & ASYNC_NORMAL_ACTIVE)
+			return (-EBUSY);
+		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+		    (info->flags & ASYNC_SESSION_LOCKOUT) &&
+		    (info->session != current->session))
+			return (-EBUSY);
+		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+		    (info->flags & ASYNC_PGRP_LOCKOUT) &&
+		    (info->pgrp != current->pgrp))
+			return (-EBUSY);
+		info->flags |= ASYNC_CALLOUT_ACTIVE;
+		return (0);
+	}
+	/*
+	 * If non-blocking mode is set, or the port is not enabled,
+	 * then make the check up front and then exit.
+	 */
+	if ((filp->f_flags & O_NONBLOCK) ||
+	    (tty->flags & (1 << TTY_IO_ERROR))) {
+		if (info->flags & ASYNC_CALLOUT_ACTIVE)
+			return (-EBUSY);
+		info->flags |= ASYNC_NORMAL_ACTIVE;
+		return (0);
+	}
+	if (info->flags & ASYNC_CALLOUT_ACTIVE) {
+		if (info->normal_termios.c_cflag & CLOCAL)
+			do_clocal = 1;
+	} else {
+		if (tty->termios->c_cflag & CLOCAL)
+			do_clocal = 1;
+	}
+
+	/*
+	 * Block waiting for the carrier detect and the line to become
+	 * free (i.e., not in use by the callout).  While we are in
+	 * this loop, info->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(&info->open_wait, &wait);
+	save_flags(flags);
+	cli();
+	if (!tty_hung_up_p(filp))
+		info->count--;
+	restore_flags(flags);
+	info->blocked_open++;
+	while (1) {
+		save_flags(flags);
+		cli();
+		if (!(info->flags & ASYNC_CALLOUT_ACTIVE))
+			outb(inb(info->base + UART_MCR) | UART_MCR_DTR | UART_MCR_RTS,
+			     info->base + UART_MCR);
+		restore_flags(flags);
+		current->state = TASK_INTERRUPTIBLE;
+		if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)) {
+#ifdef SERIAL_DO_RESTART
+			if (info->flags & ASYNC_HUP_NOTIFY)
+				retval = -EAGAIN;
+			else
+				retval = -ERESTARTSYS;
+#else
+			retval = -EAGAIN;
+#endif
+			break;
+		}
+		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
+		    !(info->flags & ASYNC_CLOSING) &&
+		    (do_clocal || (inb(info->base + UART_MSR) & UART_MSR_DCD)))
+			break;
+		if (signal_pending(current)) {
+			retval = -ERESTARTSYS;
+			break;
+		}
+		schedule();
+	}
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&info->open_wait, &wait);
+	if (!tty_hung_up_p(filp))
+		info->count++;
+	info->blocked_open--;
+	if (retval)
+		return (retval);
+	info->flags |= ASYNC_NORMAL_ACTIVE;
+	return (0);
+}
+
+static int mxser_startup(struct mxser_struct *info)
+{
+	unsigned long flags;
+	unsigned long page;
+
+	page = get_free_page(GFP_KERNEL);
+	if (!page)
+		return (-ENOMEM);
+
+	save_flags(flags);
+	cli();
+
+	if (info->flags & ASYNC_INITIALIZED) {
+		free_page(page);
+		restore_flags(flags);
+		return (0);
+	}
+	if (!info->base || !info->type) {
+		if (info->tty)
+			set_bit(TTY_IO_ERROR, &info->tty->flags);
+		free_page(page);
+		restore_flags(flags);
+		return (0);
+	}
+	if (info->xmit_buf)
+		free_page(page);
+	else
+		info->xmit_buf = (unsigned char *) page;
+
+	/*
+	 * Clear the FIFO buffers and disable them
+	 * (they will be reenabled in mxser_change_speed())
+	 */
+	if (info->xmit_fifo_size == 16)
+		outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT),
+		     info->base + UART_FCR);
+
+	/*
+	 * At this point there's no way the LSR could still be 0xFF;
+	 * if it is, then bail out, because there's likely no UART
+	 * here.
+	 */
+	if (inb(info->base + UART_LSR) == 0xff) {
+		restore_flags(flags);
+		if (suser()) {
+			if (info->tty)
+				set_bit(TTY_IO_ERROR, &info->tty->flags);
+			return (0);
+		} else
+			return (-ENODEV);
+	}
+	/*
+	 * Clear the interrupt registers.
+	 */
+	(void) inb(info->base + UART_LSR);
+	(void) inb(info->base + UART_RX);
+	(void) inb(info->base + UART_IIR);
+	(void) inb(info->base + UART_MSR);
+
+	/*
+	 * Now, initialize the UART
+	 */
+	outb(UART_LCR_WLEN8, info->base + UART_LCR);	/* reset DLAB */
+	info->MCR = UART_MCR_DTR | UART_MCR_RTS;
+	outb(info->MCR, info->base + UART_MCR);
+
+	/*
+	 * Finally, enable interrupts
+	 */
+	info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
+	outb(info->IER, info->base + UART_IER);		/* enable interrupts */
+
+	/*
+	 * And clear the interrupt registers again for luck.
+	 */
+	(void) inb(info->base + UART_LSR);
+	(void) inb(info->base + UART_RX);
+	(void) inb(info->base + UART_IIR);
+	(void) inb(info->base + UART_MSR);
+
+	if (info->tty)
+		test_and_clear_bit(TTY_IO_ERROR, &info->tty->flags);
+
+	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+
+	/*
+	 * and set the speed of the serial port
+	 */
+	mxser_change_speed(info, 0);
+
+	info->flags |= ASYNC_INITIALIZED;
+	restore_flags(flags);
+	return (0);
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts maybe disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ */
+static void mxser_shutdown(struct mxser_struct *info)
+{
+	unsigned long flags;
+
+	if (!(info->flags & ASYNC_INITIALIZED))
+		return;
+
+	save_flags(flags);
+	cli();			/* Disable interrupts */
+
+	/*
+	 * clear delta_msr_wait queue to avoid mem leaks: we may free the irq
+	 * here so the queue might never be waken up
+	 */
+	wake_up_interruptible(&info->delta_msr_wait);
+
+	/*
+	 * Free the IRQ, if necessary
+	 */
+	if (info->xmit_buf) {
+		free_page((unsigned long) info->xmit_buf);
+		info->xmit_buf = 0;
+	}
+	info->IER = 0;
+	outb(0x00, info->base + UART_IER);	/* disable all intrs */
+
+	if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
+		info->MCR &= ~(UART_MCR_DTR | UART_MCR_RTS);
+	outb(info->MCR, info->base + UART_MCR);
+
+	/* clear Rx/Tx FIFO's */
+	outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT), info->base + UART_FCR);
+	/* read data port to reset things */
+	(void) inb(info->base + UART_RX);
+
+	if (info->tty)
+		set_bit(TTY_IO_ERROR, &info->tty->flags);
+
+	info->flags &= ~ASYNC_INITIALIZED;
+	restore_flags(flags);
+}
+
+/*
+ * This routine is called to set the UART divisor registers to match
+ * the specified baud rate for a serial port.
+ */
+static int mxser_change_speed(struct mxser_struct *info,
+			      struct termios *old_termios)
+{
+	int quot = 0;
+	unsigned cflag, cval, fcr;
+	int i;
+	int ret = 0;
+	unsigned long flags;
+
+	if (!info->tty || !info->tty->termios)
+		return ret;
+	cflag = info->tty->termios->c_cflag;
+	if (!(info->base))
+		return ret;
+
+#ifndef B921600
+#define B921600 (B460800 +1)
+#endif
+	switch (cflag & (CBAUD | CBAUDEX)) {
+	case B921600:
+		i = 20;
+		break;
+	case B460800:
+		i = 19;
+		break;
+	case B230400:
+		i = 18;
+		break;
+	case B115200:
+		i = 17;
+		break;
+	case B57600:
+		i = 16;
+		break;
+	case B38400:
+		i = 15;
+		break;
+	case B19200:
+		i = 14;
+		break;
+	case B9600:
+		i = 13;
+		break;
+	case B4800:
+		i = 12;
+		break;
+	case B2400:
+		i = 11;
+		break;
+	case B1800:
+		i = 10;
+		break;
+	case B1200:
+		i = 9;
+		break;
+	case B600:
+		i = 8;
+		break;
+	case B300:
+		i = 7;
+		break;
+	case B200:
+		i = 6;
+		break;
+	case B150:
+		i = 5;
+		break;
+	case B134:
+		i = 4;
+		break;
+	case B110:
+		i = 3;
+		break;
+	case B75:
+		i = 2;
+		break;
+	case B50:
+		i = 1;
+		break;
+	default:
+		i = 0;
+		break;
+	}
+
+	if (i == 15) {
+		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+			i = 16;	/* 57600 bps */
+		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+			i = 17;	/* 115200 bps */
+
+#ifdef ASYNC_SPD_SHI
+		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+			i = 18;
+#endif
+
+#ifdef ASYNC_SPD_WARP
+		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+			i = 19;
+#endif
+	}
+	if (mxvar_baud_table[i] == 134) {
+		quot = (2 * info->baud_base / 269);
+	} else if (mxvar_baud_table[i]) {
+		quot = info->baud_base / mxvar_baud_table[i];
+		if (!quot && old_termios) {
+			/* re-calculate */
+			info->tty->termios->c_cflag &= ~CBAUD;
+			info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD);
+			switch (info->tty->termios->c_cflag & (CBAUD | CBAUDEX)) {
+			case B921600:
+				i = 20;
+				break;
+			case B460800:
+				i = 19;
+				break;
+			case B230400:
+				i = 18;
+				break;
+			case B115200:
+				i = 17;
+				break;
+			case B57600:
+				i = 16;
+				break;
+			case B38400:
+				i = 15;
+				break;
+			case B19200:
+				i = 14;
+				break;
+			case B9600:
+				i = 13;
+				break;
+			case B4800:
+				i = 12;
+				break;
+			case B2400:
+				i = 11;
+				break;
+			case B1800:
+				i = 10;
+				break;
+			case B1200:
+				i = 9;
+				break;
+			case B600:
+				i = 8;
+				break;
+			case B300:
+				i = 7;
+				break;
+			case B200:
+				i = 6;
+				break;
+			case B150:
+				i = 5;
+				break;
+			case B134:
+				i = 4;
+				break;
+			case B110:
+				i = 3;
+				break;
+			case B75:
+				i = 2;
+				break;
+			case B50:
+				i = 1;
+				break;
+			default:
+				i = 0;
+				break;
+			}
+			if (i == 15) {
+				if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+					i = 16;		/* 57600 bps */
+				if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+					i = 17;		/* 115200 bps */
+#ifdef ASYNC_SPD_SHI
+				if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+					i = 18;
+#endif
+#ifdef ASYNC_SPD_WARP
+				if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+					i = 19;
+#endif
+			}
+			if (mxvar_baud_table[i] == 134) {
+				quot = (2 * info->baud_base / 269);
+			} else if (mxvar_baud_table[i]) {
+				quot = info->baud_base / mxvar_baud_table[i];
+				if (quot == 0)
+					quot = 1;
+			} else {
+				quot = 0;
+			}
+		} else if (quot == 0)
+			quot = 1;
+	} else {
+		quot = 0;
+	}
+
+	if (quot) {
+		info->MCR |= UART_MCR_DTR;
+		save_flags(flags);
+		cli();
+		outb(info->MCR, info->base + UART_MCR);
+		restore_flags(flags);
+	} else {
+		info->MCR &= ~UART_MCR_DTR;
+		save_flags(flags);
+		cli();
+		outb(info->MCR, info->base + UART_MCR);
+		restore_flags(flags);
+		return ret;
+	}
+	/* byte size and parity */
+	switch (cflag & CSIZE) {
+	case CS5:
+		cval = 0x00;
+		break;
+	case CS6:
+		cval = 0x01;
+		break;
+	case CS7:
+		cval = 0x02;
+		break;
+	case CS8:
+		cval = 0x03;
+		break;
+	default:
+		cval = 0x00;
+		break;		/* too keep GCC shut... */
+	}
+	if (cflag & CSTOPB)
+		cval |= 0x04;
+	if (cflag & PARENB)
+		cval |= UART_LCR_PARITY;
+	if (!(cflag & PARODD))
+		cval |= UART_LCR_EPAR;
+	if ((info->type == PORT_8250) || (info->type == PORT_16450)) {
+		fcr = 0;
+	} else {
+		fcr = UART_FCR_ENABLE_FIFO;
+		switch (info->rx_trigger) {
+		case 1:
+			fcr |= UART_FCR_TRIGGER_1;
+			break;
+		case 4:
+			fcr |= UART_FCR_TRIGGER_4;
+			break;
+		case 8:
+			fcr |= UART_FCR_TRIGGER_8;
+			break;
+		default:
+			fcr |= UART_FCR_TRIGGER_14;
+		}
+	}
+
+	/* CTS flow control flag and modem status interrupts */
+	info->IER &= ~UART_IER_MSI;
+	info->MCR &= ~UART_MCR_AFE;
+	if (cflag & CRTSCTS) {
+		info->flags |= ASYNC_CTS_FLOW;
+		info->IER |= UART_IER_MSI;
+		if (info->type == PORT_16550A)
+			info->MCR |= UART_MCR_AFE;
+	} else {
+		info->flags &= ~ASYNC_CTS_FLOW;
+	}
+	outb(info->MCR, info->base + UART_MCR);
+	if (cflag & CLOCAL)
+		info->flags &= ~ASYNC_CHECK_CD;
+	else {
+		info->flags |= ASYNC_CHECK_CD;
+		info->IER |= UART_IER_MSI;
+	}
+	outb(info->IER, info->base + UART_IER);
+
+	/*
+	 * Set up parity check flag
+	 */
+	info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
+	if (I_INPCK(info->tty))
+		info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
+	if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
+		info->read_status_mask |= UART_LSR_BI;
+
+	info->ignore_status_mask = 0;
+#if 0
+	/* This should be safe, but for some broken bits of hardware... */
+	if (I_IGNPAR(info->tty)) {
+		info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
+		info->read_status_mask |= UART_LSR_PE | UART_LSR_FE;
+	}
+#endif
+	if (I_IGNBRK(info->tty)) {
+		info->ignore_status_mask |= UART_LSR_BI;
+		info->read_status_mask |= UART_LSR_BI;
+		/*
+		 * If we're ignore parity and break indicators, ignore
+		 * overruns too.  (For real raw support).
+		 */
+		if (I_IGNPAR(info->tty)) {
+			info->ignore_status_mask |= UART_LSR_OE | UART_LSR_PE | UART_LSR_FE;
+			info->read_status_mask |= UART_LSR_OE | UART_LSR_PE | UART_LSR_FE;
+		}
+	}
+	save_flags(flags);
+	cli();
+	outb(cval | UART_LCR_DLAB, info->base + UART_LCR);	/* set DLAB */
+	outb(quot & 0xff, info->base + UART_DLL);	/* LS of divisor */
+	outb(quot >> 8, info->base + UART_DLM);		/* MS of divisor */
+	outb(cval, info->base + UART_LCR);	/* reset DLAB */
+	outb(fcr, info->base + UART_FCR);	/* set fcr */
+	restore_flags(flags);
+
+	return ret;
+}
+
+/*
+ * ------------------------------------------------------------
+ * friends of mxser_ioctl()
+ * ------------------------------------------------------------
+ */
+static int mxser_get_serial_info(struct mxser_struct *info,
+				 struct serial_struct *retinfo)
+{
+	struct serial_struct tmp;
+
+	if (!retinfo)
+		return (-EFAULT);
+	memset(&tmp, 0, sizeof(tmp));
+	tmp.type = info->type;
+	tmp.line = info->port;
+	tmp.port = info->base;
+	tmp.irq = info->irq;
+	tmp.flags = info->flags;
+	tmp.baud_base = info->baud_base;
+	tmp.close_delay = info->close_delay;
+	tmp.closing_wait = info->closing_wait;
+	tmp.custom_divisor = info->custom_divisor;
+	tmp.hub6 = 0;
+	copy_to_user(retinfo, &tmp, sizeof(*retinfo));
+	return (0);
+}
+
+static int mxser_set_serial_info(struct mxser_struct *info,
+				 struct serial_struct *new_info)
+{
+	struct serial_struct new_serial;
+	unsigned int flags;
+	int retval = 0;
+
+	if (!new_info || !info->base)
+		return (-EFAULT);
+	copy_from_user(&new_serial, new_info, sizeof(new_serial));
+
+	if ((new_serial.irq != info->irq) ||
+	    (new_serial.port != info->base) ||
+	    (new_serial.type != info->type) ||
+	    (new_serial.custom_divisor != info->custom_divisor) ||
+	    (new_serial.baud_base != info->baud_base))
+		return (-EPERM);
+
+	flags = info->flags & ASYNC_SPD_MASK;
+
+	if (!suser()) {
+		if ((new_serial.baud_base != info->baud_base) ||
+		    (new_serial.close_delay != info->close_delay) ||
+		    ((new_serial.flags & ~ASYNC_USR_MASK) !=
+		     (info->flags & ~ASYNC_USR_MASK)))
+			return (-EPERM);
+		info->flags = ((info->flags & ~ASYNC_USR_MASK) |
+			       (new_serial.flags & ASYNC_USR_MASK));
+	} else {
+		/*
+		 * OK, past this point, all the error checking has been done.
+		 * At this point, we start making changes.....
+		 */
+		info->flags = ((info->flags & ~ASYNC_FLAGS) |
+			       (new_serial.flags & ASYNC_FLAGS));
+		info->close_delay = new_serial.close_delay * HZ / 100;
+		info->closing_wait = new_serial.closing_wait * HZ / 100;
+	}
+
+	if (info->flags & ASYNC_INITIALIZED) {
+		if (flags != (info->flags & ASYNC_SPD_MASK)) {
+			mxser_change_speed(info, 0);
+		}
+	} else
+		retval = mxser_startup(info);
+	return (retval);
+}
+
+/*
+ * mxser_get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ *          is emptied.  On bus types like RS485, the transmitter must
+ *          release the bus after transmitting. This must be done when
+ *          the transmit shift register is empty, not be done when the
+ *          transmit holding register is empty.  This functionality
+ *          allows an RS485 driver to be written in user space.
+ */
+static int mxser_get_lsr_info(struct mxser_struct *info, unsigned int *value)
+{
+	unsigned char status;
+	unsigned int result;
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	status = inb(info->base + UART_LSR);
+	restore_flags(flags);
+	result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
+	put_user(result, value);
+	return (0);
+}
+
+/*
+ * This routine sends a break character out the serial port.
+ */
+static void mxser_send_break(struct mxser_struct *info, int duration)
+{
+	unsigned long flags;
+	if (!info->base)
+		return;
+	current->state = TASK_INTERRUPTIBLE;
+	save_flags(flags);
+	cli();
+	outb(inb(info->base + UART_LCR) | UART_LCR_SBC, info->base + UART_LCR);
+	schedule_timeout(duration);
+	outb(inb(info->base + UART_LCR) & ~UART_LCR_SBC, info->base + UART_LCR);
+	restore_flags(flags);
+}
+
+static int mxser_get_modem_info(struct mxser_struct *info,
+				unsigned int *value)
+{
+	unsigned char control, status;
+	unsigned int result;
+	unsigned long flags;
+
+	control = info->MCR;
+	save_flags(flags);
+	cli();
+	status = inb(info->base + UART_MSR);
+	if (status & UART_MSR_ANY_DELTA)
+		mxser_check_modem_status(info, status);
+	restore_flags(flags);
+	result = ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) |
+	    ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) |
+	    ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) |
+	    ((status & UART_MSR_RI) ? TIOCM_RNG : 0) |
+	    ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) |
+	    ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
+	put_user(result, value);
+	return (0);
+}
+
+static int mxser_set_modem_info(struct mxser_struct *info, unsigned int cmd,
+				unsigned int *value)
+{
+	unsigned int arg;
+	unsigned long flags;
+
+	if(get_user(arg, value))
+		return -EFAULT;
+	switch (cmd) {
+	case TIOCMBIS:
+		if (arg & TIOCM_RTS)
+			info->MCR |= UART_MCR_RTS;
+		if (arg & TIOCM_DTR)
+			info->MCR |= UART_MCR_DTR;
+		break;
+	case TIOCMBIC:
+		if (arg & TIOCM_RTS)
+			info->MCR &= ~UART_MCR_RTS;
+		if (arg & TIOCM_DTR)
+			info->MCR &= ~UART_MCR_DTR;
+		break;
+	case TIOCMSET:
+		info->MCR = ((info->MCR & ~(UART_MCR_RTS | UART_MCR_DTR)) |
+			     ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0) |
+			     ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0));
+		break;
+	default:
+		return (-EINVAL);
+	}
+	save_flags(flags);
+	cli();
+	outb(info->MCR, info->base + UART_MCR);
+	restore_flags(flags);
+	return (0);
+}
+
+static int mxser_read_register(int, unsigned short *);
+static int mxser_program_mode(int);
+static void mxser_normal_mode(int);
+
+static int mxser_get_ISA_conf(int cap, struct mxser_hwconf *hwconf)
+{
+	int id, i, bits;
+	unsigned short regs[16], irq;
+	unsigned char scratch, scratch2;
+
+	id = mxser_read_register(cap, regs);
+	if (id == C168_ASIC_ID)
+		hwconf->board_type = MXSER_BOARD_C168_ISA;
+	else if (id == C104_ASIC_ID)
+		hwconf->board_type = MXSER_BOARD_C104_ISA;
+	else if (id == CI104J_ASIC_ID)
+		hwconf->board_type = MXSER_BOARD_CI104J;
+	else
+		return (0);
+	irq = regs[9] & 0x0F;
+	irq = irq | (irq << 4);
+	irq = irq | (irq << 8);
+	if ((irq != regs[9]) || ((id == 1) && (irq != regs[10]))) {
+		return (MXSER_ERR_IRQ_CONFLIT);
+	}
+	if (!irq) {
+		return (MXSER_ERR_IRQ);
+	}
+	for (i = 0; i < 8; i++)
+		hwconf->ioaddr[i] = (int) regs[i + 1] & 0xFFF8;
+	hwconf->irq = (int) (irq & 0x0F);
+	if ((regs[12] & 0x80) == 0) {
+		return (MXSER_ERR_VECTOR);
+	}
+	hwconf->vector = (int) regs[11];	/* interrupt vector */
+	if (id == 1)
+		hwconf->vector_mask = 0x00FF;
+	else
+		hwconf->vector_mask = 0x000F;
+	for (i = 7, bits = 0x0100; i >= 0; i--, bits <<= 1) {
+		if (regs[12] & bits)
+			hwconf->baud_base[i] = 921600;
+		else
+			hwconf->baud_base[i] = 115200;
+	}
+	scratch2 = inb(cap + UART_LCR) & (~UART_LCR_DLAB);
+	outb(scratch2 | UART_LCR_DLAB, cap + UART_LCR);
+	outb(0, cap + UART_EFR);	/* EFR is the same as FCR */
+	outb(scratch2, cap + UART_LCR);
+	outb(UART_FCR_ENABLE_FIFO, cap + UART_FCR);
+	scratch = inb(cap + UART_IIR);
+	if (scratch & 0xC0)
+		hwconf->uart_type = PORT_16550A;
+	else
+		hwconf->uart_type = PORT_16450;
+	if (id == 1)
+		hwconf->ports = 8;
+	else
+		hwconf->ports = 4;
+	return (hwconf->ports);
+}
+
+#define CHIP_SK 	0x01	/* Serial Data Clock  in Eprom */
+#define CHIP_DO 	0x02	/* Serial Data Output in Eprom */
+#define CHIP_CS 	0x04	/* Serial Chip Select in Eprom */
+#define CHIP_DI 	0x08	/* Serial Data Input  in Eprom */
+#define EN_CCMD 	0x000	/* Chip's command register     */
+#define EN0_RSARLO	0x008	/* Remote start address reg 0  */
+#define EN0_RSARHI	0x009	/* Remote start address reg 1  */
+#define EN0_RCNTLO	0x00A	/* Remote byte count reg WR    */
+#define EN0_RCNTHI	0x00B	/* Remote byte count reg WR    */
+#define EN0_DCFG	0x00E	/* Data configuration reg WR   */
+#define EN0_PORT	0x010	/* Rcv missed frame error counter RD */
+#define ENC_PAGE0	0x000	/* Select page 0 of chip registers   */
+#define ENC_PAGE3	0x0C0	/* Select page 3 of chip registers   */
+static int mxser_read_register(int port, unsigned short *regs)
+{
+	int i, k, value, id;
+	unsigned int j;
+
+	id = mxser_program_mode(port);
+	if (id < 0)
+		return (id);
+	for (i = 0; i < 14; i++) {
+		k = (i & 0x3F) | 0x180;
+		for (j = 0x100; j > 0; j >>= 1) {
+			outb(CHIP_CS, port);
+			if (k & j) {
+				outb(CHIP_CS | CHIP_DO, port);
+				outb(CHIP_CS | CHIP_DO | CHIP_SK, port);	/* A? bit of read */
+			} else {
+				outb(CHIP_CS, port);
+				outb(CHIP_CS | CHIP_SK, port);	/* A? bit of read */
+			}
+		}
+		(void) inb(port);
+		value = 0;
+		for (k = 0, j = 0x8000; k < 16; k++, j >>= 1) {
+			outb(CHIP_CS, port);
+			outb(CHIP_CS | CHIP_SK, port);
+			if (inb(port) & CHIP_DI)
+				value |= j;
+		}
+		regs[i] = value;
+		outb(0, port);
+	}
+	mxser_normal_mode(port);
+	return (id);
+}
+
+static int mxser_program_mode(int port)
+{
+	int id, i, j, n;
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	outb(0, port);
+	outb(0, port);
+	outb(0, port);
+	(void) inb(port);
+	(void) inb(port);
+	outb(0, port);
+	(void) inb(port);
+	restore_flags(flags);
+	id = inb(port + 1) & 0x1F;
+	if ((id != C168_ASIC_ID) && (id != C104_ASIC_ID) && (id != CI104J_ASIC_ID))
+		return (-1);
+	for (i = 0, j = 0; i < 4; i++) {
+		n = inb(port + 2);
+		if (n == 'M') {
+			j = 1;
+		} else if ((j == 1) && (n == 1)) {
+			j = 2;
+			break;
+		} else
+			j = 0;
+	}
+	if (j != 2)
+		id = -2;
+	return (id);
+}
+
+static void mxser_normal_mode(int port)
+{
+	int i, n;
+
+	outb(0xA5, port + 1);
+	outb(0x80, port + 3);
+	outb(12, port + 0);	/* 9600 bps */
+	outb(0, port + 1);
+	outb(0x03, port + 3);	/* 8 data bits */
+	outb(0x13, port + 4);	/* loop back mode */
+	for (i = 0; i < 16; i++) {
+		n = inb(port + 5);
+		if ((n & 0x61) == 0x60)
+			break;
+		if ((n & 1) == 1)
+			(void) inb(port);
+	}
+	outb(0x00, port + 4);
+}
diff -urN linux-2.2.14-pre16/drivers/char/tty_io.c linux-2.2.14-pre17/drivers/char/tty_io.c
--- linux-2.2.14-pre16/drivers/char/tty_io.c	2003-08-15 15:10:01.000000000 -0700
+++ linux-2.2.14-pre17/drivers/char/tty_io.c	2003-08-15 15:10:02.000000000 -0700
@@ -2209,6 +2209,12 @@
         rs_8xx_init();
 #endif /* CONFIG_8xx */
 	pty_init();
+#ifdef CONFIG_MOXA_SMARTIO
+	mxser_init();
+#endif	
+#ifdef CONFIG_MOXA_INTELLIO
+	moxa_init();
+#endif	
 #ifdef CONFIG_VT
 	vcs_init();
 #endif
diff -urN linux-2.2.14-pre16/drivers/net/sis900.c linux-2.2.14-pre17/drivers/net/sis900.c
--- linux-2.2.14-pre16/drivers/net/sis900.c	2003-08-15 15:10:01.000000000 -0700
+++ linux-2.2.14-pre17/drivers/net/sis900.c	2003-08-15 15:10:02.000000000 -0700
@@ -1,5 +1,5 @@
 /* sis900.c: A SiS 900/7016 PCI Fast Ethernet driver for Linux.
-   Silicon Integrated System Corporation 
+   Copyright 1999 Silicon Integrated System Corporation 
    Revision:	1.05	Aug 7 1999
    
    Modified from the driver which is originally written by Donald Becker. 
@@ -18,6 +18,8 @@
    preliminary Rev. 1.0 Jan. 18, 1998
    http://www.sis.com.tw/support/databook.htm
    
+   Rev 1.06.02 Nov. 23 1999 Ollie Lho 
+   Rev 1.06.01 Nov. 16 1999 Ollie Lho CRC calculation provide by Joseph Zbiciak (im14u2c@primenet.com)
    Rev 1.06 Nov. 4 1999 Ollie Lho (ollie@sis.com.tw) Second release
    Rev 1.05.05 Oct. 29 1999 Ollie Lho (ollie@sis.com.tw) Single buffer Tx/Rx  
    Chin-Shan Li (lcs@sis.com.tw) Added AMD Am79c901 HomePNA PHY support
@@ -47,7 +49,7 @@
 #include "sis900.h"
 
 static const char *version =
-"sis900.c: v1.06  11/04/99\n";
+"sis900.c: v1.06.03  12/23/99\n";
 
 static int max_interrupt_work = 20;
 #define sis900_debug debug
@@ -221,17 +223,18 @@
 	if (did_version++ == 0)
 		printk(KERN_INFO "%s", version);
 
+	if ((net_dev = init_etherdev(net_dev, 0)) == NULL)
+		return NULL;
+
 	/* check to see if we have sane EEPROM */
 	signature = (u16) read_eeprom(ioaddr, EEPROMSignature);    
 	if (signature == 0xffff || signature == 0x0000) {
-		printk (KERN_INFO "%s: Error EERPOM read %x\n", 
+		printk (KERN_INFO "%s: Error EEPROM read: %x\n",
 			net_dev->name, signature);
+		unregister_netdevice(net_dev);
 		return NULL;
 	}
 
-	if ((net_dev = init_etherdev(net_dev, 0)) == NULL)
-		return NULL;
-
 	printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", net_dev->name, mac->name,
 	       ioaddr, irq);
 
@@ -509,7 +512,7 @@
         net_dev->start = 1;
 
         /* Enable all known interrupts by setting the interrupt mask. */
-	outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxOK), ioaddr + imr);
+	outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxIDLE), ioaddr + imr);
         outl(RxENA, ioaddr + cr);
         outl(IE, ioaddr + ier);
 
@@ -770,7 +773,6 @@
 			       "full" : "half");
 		else
 			printk(KERN_INFO "%s: Media Link Off\n", net_dev->name);
-			
 	}
 	else {
 		/* HomePNA */
@@ -787,6 +789,7 @@
 {
         struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;
         long ioaddr = net_dev->base_addr;
+	int i;
 
 	printk(KERN_INFO "%s: Transmit timeout, status %8.8x %8.8x \n",
 	       net_dev->name, inl(ioaddr + cr), inl(ioaddr + isr));
@@ -794,14 +797,25 @@
         /* Disable interrupts by clearing the interrupt mask. */
         outl(0x0000, ioaddr + imr);
 
-        sis_priv->cur_rx = 0;
+	/* discard unsent packets, should this code section be protected by
+	   cli(), sti() ?? */
+	sis_priv->dirty_tx = sis_priv->cur_tx = 0;
+	for (i = 0; i < NUM_TX_DESC; i++) {
+		if (sis_priv->tx_skbuff[i] != NULL) {
+		    dev_kfree_skb(sis_priv->tx_skbuff[i]);
+		    sis_priv->tx_skbuff[i] = 0;
+			sis_priv->tx_ring[i].cmdsts = 0;
+			sis_priv->tx_ring[i].bufptr = 0;
+			sis_priv->stats.tx_dropped++;
+		}
+	}
         net_dev->trans_start = jiffies;
-        sis_priv->stats.tx_errors++;
+	net_dev->tbusy = sis_priv->tx_full = 0;
 
 	/* FIXME: Should we restart the transmission thread here  ?? */
 
         /* Enable all known interrupts by setting the interrupt mask. */
-        outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxOK), ioaddr + imr);
+	outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxIDLE), ioaddr + imr);
         return;
 }
 
@@ -876,13 +890,7 @@
         do {
                 status = inl(ioaddr + isr);
 		
-                if (sis900_debug > 3)
-			printk(KERN_INFO "%s: entering interrupt, "
-			       "original status = %#8.8x, "
-			       "new status = %#8.8x.\n",
-			       net_dev->name, status, inl(ioaddr + isr));
-
-                if ((status & (HIBERR|TxURN|TxERR|TxOK|RxORN|RxERR|RxOK)) == 0)
+		if ((status & (HIBERR|TxURN|TxERR|TxIDLE|RxORN|RxERR|RxOK)) == 0)
 			/* nothing intresting happened */
                         break;
 
@@ -891,7 +899,7 @@
 			/* Rx interrupt */
                         sis900_rx(net_dev);
 
-                if (status & (TxURN | TxERR | TxOK))
+		if (status & (TxURN | TxERR | TxIDLE))
 			/* Tx interrupt */
 			sis900_finish_xmit(net_dev);
 
@@ -961,6 +969,9 @@
                 } else {
 			struct sk_buff * skb;
 			
+			/* This situation should never happen, but due to
+			   some unknow bugs, it is possible that
+			   we are working on NULL sk_buff :-( */
 			if (sis_priv->rx_skbuff[entry] == NULL) {
 				printk(KERN_INFO "%s: NULL pointer " 
 				       "encountered in Rx ring, skipping\n",
@@ -1033,7 +1044,9 @@
 	        tx_status = sis_priv->tx_ring[entry].cmdsts;
 		
 		if (tx_status & OWN) {
-			/* The packet is not transmited yet (owned by hardware) ! */
+			/* The packet is not transmited yet (owned by hardware) !
+			   Note: the interrupt is generated only when Tx Machine
+			   is idle, so this is an almost impossible case */
 			break;
 		}
 		
@@ -1054,8 +1067,6 @@
 				sis_priv->stats.tx_window_errors++;
 		} else {
 			/* packet successfully transmited */
-			if (sis900_debug > 3)
-				printk(KERN_INFO "Tx Transmit OK\n");
 			sis_priv->stats.collisions += (tx_status & COLCNT) >> 16;
 			sis_priv->stats.tx_bytes += tx_status & DSIZE;
 			sis_priv->stats.tx_packets++;
@@ -1069,8 +1080,8 @@
 	
 	if (sis_priv->tx_full && net_dev->tbusy && 
 	    sis_priv->cur_tx - sis_priv->dirty_tx < NUM_TX_DESC - 4) {
-		/* The ring is no longer full, clear tbusy, tx_full and schedule 
-		   more transmission by marking NET_BH */
+		/* The ring is no longer full, clear tbusy, tx_full and 
+		   schedule more transmission by marking NET_BH */
 		sis_priv->tx_full = 0;
 		clear_bit(0, (void *)&net_dev->tbusy);
 		mark_bh(NET_BH);
@@ -1153,11 +1164,13 @@
 {
 
 /* what is the correct value of the POLYNOMIAL ??
-   Donald Becker use 0x04C11DB7U */
-#define POLYNOMIAL 0x04C11DB6L
+   Donald Becker use 0x04C11DB7U
+   Joseph Zbiciak im14u2c@primenet.com gives me the
+   correct answer, thank you Joe !! */
+#define POLYNOMIAL 0x04C11DB7L
 	u32 crc = 0xffffffff, msb;
 	int  i, j;
-	u8  byte;
+	u32 byte;
 
 	for (i = 0; i < 6; i++) {
 		byte = *addr++;
@@ -1166,7 +1179,6 @@
 			crc <<= 1;
 			if (msb ^ (byte & 1)) {
 				crc ^= POLYNOMIAL;
-				crc |= 1;
 			}
 			byte >>= 1;
 		}
@@ -1189,13 +1201,13 @@
                         mc_filter[i] = 0xffff;
         } else if ((net_dev->mc_count > multicast_filter_limit) ||
 		   (net_dev->flags & IFF_ALLMULTI)) {
-		/* too many multicast addresses or accept all multicast packet */
+		/* too many multicast addresses or accept all multicast packets */
                 rx_mode = RFAAB | RFAAM;
                 for (i = 0; i < 8; i++)
                         mc_filter[i] = 0xffff;
         } else {
-		/* Accept Broadcast packet, destination address matchs our MAC address,
-		   use Receive Filter to reject unwanted MCAST packet */
+		/* Accept Broadcast packets, destination addresses match our MAC address,
+		   use Receive Filter to reject unwanted MCAST packets */
                 struct dev_mc_list *mclist;
                 rx_mode = RFAAB;
                 for (i = 0; i < 8; i++)
@@ -1208,7 +1220,7 @@
 
 	/* update Multicast Hash Table in Receive Filter */
         for (i = 0; i < 8; i++) {
-		/* why plus 0x04 ??, I don't know, UNDOCUMENT FEATURE ?? */
+		/* why plus 0x04 ??, That makes the correct value for hash table. */
                 outl((u32)(0x00000004+i) << RFADDR_shift, ioaddr + rfcr);
                 outl(mc_filter[i], ioaddr + rfdr);
         }
diff -urN linux-2.2.14-pre16/drivers/net/sis900.h linux-2.2.14-pre17/drivers/net/sis900.h
--- linux-2.2.14-pre16/drivers/net/sis900.h	2003-08-15 15:10:01.000000000 -0700
+++ linux-2.2.14-pre17/drivers/net/sis900.h	2003-08-15 15:10:02.000000000 -0700
@@ -92,8 +92,8 @@
 
 /* recevie FIFO thresholds */
 #define RxDRNT_shift     1
-#define RxDRNT_100	24	/* 3/4 FIFO size */
-#define RxDRNT_10		16 	/* 1/2 FIFO size */
+#define RxDRNT_100	16	/* 1/2 FIFO size */
+#define RxDRNT_10		24 	/* 3/4 FIFO size */
 
 enum sis900_reveive_config_register_bits {
 	RxAEP  = 0x80000000, RxARP = 0x40000000, RxATX = 0x10000000,
diff -urN linux-2.2.14-pre16/drivers/net/tulip.c linux-2.2.14-pre17/drivers/net/tulip.c
--- linux-2.2.14-pre16/drivers/net/tulip.c	2003-08-15 15:10:01.000000000 -0700
+++ linux-2.2.14-pre17/drivers/net/tulip.c	2003-08-15 15:10:02.000000000 -0700
@@ -2746,9 +2746,7 @@
 			oi++;
 		}
 		if (tx > maxtx || rx > maxrx || oi > maxoi) {
-#if 0
 			if (tulip_debug > 1)
-#endif
 				printk(KERN_WARNING "%s: Too much work during an interrupt, "
 					   "csr5=0x%8.8x. (%lu) (%d,%d,%d)\n", dev->name, csr5, tp->nir, tx, rx, oi);
 			/* Acknowledge all interrupt sources. */
@@ -2768,9 +2766,11 @@
 	/* check if we card is in suspend mode */
 	entry = tp->dirty_rx % RX_RING_SIZE;
 	if (tp->rx_skbuff[entry] == NULL) {
-		printk(KERN_WARNING "%s: in rx suspend mode: (%lu) (tp->cur_rx = %u, ttimer = %d, rx = %d) go/stay in suspend mode\n", dev->name, tp->nir, tp->cur_rx, tp->ttimer, rx);
+		if (tulip_debug > 1)
+			printk(KERN_WARNING "%s: in rx suspend mode: (%lu) (tp->cur_rx = %u, ttimer = %d, rx = %d) go/stay in suspend mode\n", dev->name, tp->nir, tp->cur_rx, tp->ttimer, rx);
 		if (tp->ttimer == 0 || (inl(ioaddr + CSR11) & 0xffff) == 0) {
-			printk(KERN_WARNING "%s: in rx suspend mode: (%lu) set timer\n", dev->name, tp->nir);
+			if (tulip_debug > 1)
+				printk(KERN_WARNING "%s: in rx suspend mode: (%lu) set timer\n", dev->name, tp->nir);
 			outl(tulip_tbl[tp->chip_id].valid_intrs | TimerInt,
 				ioaddr + CSR7);
 			outl(TimerInt, ioaddr + CSR5);
diff -urN linux-2.2.14-pre16/drivers/scsi/aha1542.c linux-2.2.14-pre17/drivers/scsi/aha1542.c
--- linux-2.2.14-pre16/drivers/scsi/aha1542.c	1999-10-19 17:14:01.000000000 -0700
+++ linux-2.2.14-pre17/drivers/scsi/aha1542.c	2003-08-15 15:10:02.000000000 -0700
@@ -482,7 +482,11 @@
       }
       
       my_done = SCtmp->scsi_done;
-      if (SCtmp->host_scribble) scsi_free(SCtmp->host_scribble, 512);
+      if (SCtmp->host_scribble)
+      {
+      	scsi_free(SCtmp->host_scribble, 512);
+      	SCtmp->host_scribble = 0;
+      }
       
       /* Fetch the sense data, and tuck it away, in the required slot.  The
 	 Adaptec automatically fetches it, and there is no guarantee that
diff -urN linux-2.2.14-pre16/drivers/telephony/ixj.h linux-2.2.14-pre17/drivers/telephony/ixj.h
--- linux-2.2.14-pre16/drivers/telephony/ixj.h	2003-08-15 15:10:01.000000000 -0700
+++ linux-2.2.14-pre17/drivers/telephony/ixj.h	2003-08-15 15:10:03.000000000 -0700
@@ -29,7 +29,7 @@
 #include <asm/types.h>
 #endif
 
-#include "ixjuser.h"
+#include <linux/ixjuser.h>
 #include <linux/phonedev.h>
 
 typedef __u16 WORD;
diff -urN linux-2.2.14-pre16/drivers/telephony/ixjuser.h linux-2.2.14-pre17/drivers/telephony/ixjuser.h
--- linux-2.2.14-pre16/drivers/telephony/ixjuser.h	2003-08-15 15:10:01.000000000 -0700
+++ linux-2.2.14-pre17/drivers/telephony/ixjuser.h	1969-12-31 16:00:00.000000000 -0800
@@ -1,629 +0,0 @@
-/*
- *    ixjuser.h
- *
- *    User-space include file for the Internet PhoneJACK and
- *    Internet LineJACK Telephony Cards.
- *
- *    (c) Copyright 1999 Quicknet Technologies, Inc.
- *
- *    This program is free software; you can redistribute it and/or
- *    modify it under the terms of the GNU General Public License
- *    as published by the Free Software Foundation; either version
- *    2 of the License, or (at your option) any later version.
- *
- * Author:          Ed Okerson, <eokerson@quicknet.net>
- *    
- * Contributors:    Greg Herlein, <gherlein@quicknet.net>
- *                  David W. Erhart, <derhart@quicknet.net>
- *                  John Sellers, <jsellers@quicknet.net>
- *                  Mike Preston, <mpreston@quicknet.net>
- *
- * More information about the hardware related to this driver can be found
- * at our website:    http://www.quicknet.net
- *
- * Fixes:
- */
-
-static char ixjuser_h_rcsid[] = "$Id: ixjuser.h,v 3.4 1999/12/16 22:18:36 root Exp root $";
-
-#include <linux/telephony.h>
-
-/***************************************************************************
-
-  If you use the IXJCTL_TESTRAM command, the card must be power
-  cycled to reset the SRAM values before futher use.
-
-***************************************************************************/
-#define IXJCTL_DSP_RESET 		_IO  ('q', 0xC0)
-
-#define IXJCTL_RING         PHONE_RING
-#define IXJCTL_HOOKSTATE    PHONE_HOOKSTATE
-#define IXJCTL_MAXRINGS			PHONE_MAXRINGS
-#define IXJCTL_RING_CADENCE	PHONE_RING_CADENCE
-#define IXJCTL_RING_START		PHONE_RING_START
-#define IXJCTL_RING_STOP		PHONE_RING_STOP
-
-#define IXJCTL_CARDTYPE			_IOR ('q', 0xC1, int)
-#define IXJCTL_SERIAL			  _IOR ('q', 0xC2, int)
-#define IXJCTL_DSP_TYPE     _IOR ('q', 0xC3, int)
-#define IXJCTL_DSP_VERSION  _IOR ('q', 0xC4, int)
-#define IXJCTL_DSP_IDLE			_IO  ('q', 0xC5)
-#define IXJCTL_TESTRAM			_IO  ('q', 0xC6)
-
-/******************************************************************************
-*
-* This group of IOCTLs deal with the record settings of the DSP
-*
-* The IXJCTL_REC_DEPTH command sets the internal buffer depth of the DSP.
-* Setting a lower depth reduces latency, but increases the demand of the
-* application to service the driver without frame loss.  The DSP has 480
-* bytes of physical buffer memory for the record channel so the true
-* maximum limit is determined by how many frames will fit in the buffer.
-*
-* 1 uncompressed (480 byte) 16-bit linear frame.
-* 2 uncompressed (240 byte) 8-bit A-law/mu-law frames.
-* 15 TrueSpeech 8.5 frames.
-* 20 TrueSpeech 6.3,5.3,4.8 or 4.1 frames.
-*
-* The default in the driver is currently set to 2 frames.
-*
-* The IXJCTL_REC_VOLUME and IXJCTL_PLAY_VOLUME commands both use a Q8
-* number as a parameter, 0x100 scales the signal by 1.0, 0x200 scales the
-* signal by 2.0, 0x80 scales the signal by 0.5.  No protection is given
-* against over-scaling, if the multiplication factor times the input
-* signal exceeds 16 bits, overflow distortion will occur.  The default
-* setting is 0x100 (1.0).
-*
-* The IXJCTL_REC_LEVEL returns the average signal level (not r.m.s.) on
-* the most recently recorded frame as a 16 bit value.
-******************************************************************************/
-
-#define IXJCTL_REC_CODEC                PHONE_REC_CODEC
-#define IXJCTL_REC_START                PHONE_REC_START
-#define IXJCTL_REC_STOP                 PHONE_REC_STOP
-#define IXJCTL_REC_DEPTH		PHONE_REC_DEPTH
-#define IXJCTL_FRAME			PHONE_FRAME
-#define IXJCTL_REC_VOLUME		PHONE_REC_VOLUME
-#define IXJCTL_REC_LEVEL		PHONE_REC_LEVEL
-
-typedef enum {
-	f300_640 = 4, f300_500, f1100, f350, f400, f480, f440, f620, f20_50,
-	f133_200, f300, f300_420, f330, f300_425, f330_440, f340, f350_400,
-	f350_440, f350_450, f360, f380_420, f392, f400_425, f400_440, f400_450,
-	f420, f425, f425_450, f425_475, f435, f440_450, f440_480, f445, f450,
-	f452, f475, f480_620, f494, f500, f520, f523, f525, f540_660, f587,
-	f590, f600, f660, f700, f740, f750, f750_1450, f770, f800, f816, f850,
-	f857_1645, f900, f900_1300, f935_1215, f941_1477, f942, f950, f950_1400,
-	f975, f1000, f1020, f1050, f1100_1750, f1140, f1200, f1209, f1330, f1336,
-	lf1366, f1380, f1400, f1477, f1600, f1633_1638, f1800, f1860
-} IXJ_FILTER_FREQ;
-
-typedef struct {
-	unsigned int filter;
-	IXJ_FILTER_FREQ freq;
-	char enable;
-} IXJ_FILTER;
-
-#define IXJCTL_SET_FILTER		_IOW ('q', 0xC7, IXJ_FILTER *)
-#define IXJCTL_GET_FILTER_HIST		_IOW ('q', 0xC8, int)
-/******************************************************************************
-*
-* This IOCTL allows you to reassign values in the tone index table.  The
-* tone table has 32 entries (0 - 31), but the driver only allows entries
-* 13 - 27 to be modified, entry 0 is reserved for silence and 1 - 12 are
-* the standard DTMF digits and 28 - 31 are the DTMF tones for A, B, C & D.
-* The positions used internally for Call Progress Tones are as follows:
-*    Dial Tone   - 25
-*    Ring Back   - 26
-*    Busy Signal - 27
-*
-* The freq values are calculated as:
-* freq = cos(2 * PI * frequency / 8000)
-*
-* The most commonly needed values are already calculated and listed in the
-* enum IXJ_TONE_FREQ.  Each tone index can have two frequencies with
-* different gains, if you are only using a single frequency set the unused
-* one to 0.
-*
-* The gain values range from 0 to 15 indicating +6dB to -24dB in 2dB
-* increments.
-*
-******************************************************************************/
-
-typedef enum {
-	hz20 = 0x7ffa,
-	hz50 = 0x7fe5,
-	hz133 = 0x7f4c,
-	hz200 = 0x7e6b,
-	hz261 = 0x7d50,		/* .63 C1  */
-	hz277 = 0x7cfa,		/* .18 CS1 */
-	hz293 = 0x7c9f,		/* .66 D1  */
-	hz300 = 0x7c75,
-	hz311 = 0x7c32,		/* .13 DS1 */
-	hz329 = 0x7bbf,		/* .63 E1  */
-	hz330 = 0x7bb8,
-	hz340 = 0x7b75,
-	hz349 = 0x7b37,		/* .23 F1  */
-	hz350 = 0x7b30,
-	hz360 = 0x7ae9,
-	hz369 = 0x7aa8,		/* .99 FS1 */
-	hz380 = 0x7a56,
-	hz392 = 0x79fa,		/* .00 G1  */
-	hz400 = 0x79bb,
-	hz415 = 0x7941,		/* .30 GS1 */
-	hz420 = 0x7918,
-	hz425 = 0x78ee,
-	hz435 = 0x7899,
-	hz440 = 0x786d,		/* .00 A1  */
-	hz445 = 0x7842,
-	hz450 = 0x7815,
-	hz452 = 0x7803,
-	hz466 = 0x7784,		/* .16 AS1 */
-	hz475 = 0x7731,
-	hz480 = 0x7701,
-	hz493 = 0x7685,		/* .88 B1  */
-	hz494 = 0x767b,
-	hz500 = 0x7640,
-	hz520 = 0x7578,
-	hz523 = 0x7559,		/* .25 C2  */
-	hz525 = 0x7544,
-	hz540 = 0x74a7,
-	hz554 = 0x7411,		/* .37 CS2 */
-	hz587 = 0x72a1,		/* .33 D2  */
-	hz590 = 0x727f,
-	hz600 = 0x720b,
-	hz620 = 0x711e,
-	hz622 = 0x7106,		/* .25 DS2 */
-	hz659 = 0x6f3b,		/* .26 E2  */
-	hz660 = 0x6f2e,
-	hz698 = 0x6d3d,		/* .46 F2  */
-	hz700 = 0x6d22,
-	hz739 = 0x6b09,		/* .99 FS2 */
-	hz740 = 0x6afa,
-	hz750 = 0x6a6c,
-	hz770 = 0x694b,
-	hz783 = 0x688b,		/* .99 G2  */
-	hz800 = 0x678d,
-	hz816 = 0x6698,
-	hz830 = 0x65bf,		/* .61 GS2 */
-	hz850 = 0x6484,
-	hz857 = 0x6414,
-	hz880 = 0x629f,		/* .00 A2  */
-	hz900 = 0x6154,
-	hz932 = 0x5f35,		/* .33 AS2 */
-	hz935 = 0x5f01,
-	hz941 = 0x5e9a,
-	hz942 = 0x5e88,
-	hz950 = 0x5dfd,
-	hz975 = 0x5c44,
-	hz1000 = 0x5a81,
-	hz1020 = 0x5912,
-	hz1050 = 0x56e2,
-	hz1100 = 0x5320,
-	hz1140 = 0x5007,
-	hz1200 = 0x4b3b,
-	hz1209 = 0x4a80,
-	hz1215 = 0x4a02,
-	hz1250 = 0x471c,
-	hz1300 = 0x42e0,
-	hz1330 = 0x4049,
-	hz1336 = 0x3fc4,
-	hz1366 = 0x3d22,
-	hz1380 = 0x3be4,
-	hz1400 = 0x3a1b,
-	hz1450 = 0x3596,
-	hz1477 = 0x331c,
-	hz1500 = 0x30fb,
-	hz1600 = 0x278d,
-	hz1633 = 0x2462,
-	hz1638 = 0x23e7,
-	hz1645 = 0x233a,
-	hz1750 = 0x18f8,
-	hz1800 = 0x1405,
-	hz1860 = 0xe0b,
-	hz2100 = 0xf5f6,
-	hz2450 = 0xd3b3
-} IXJ_FREQ;
-
-typedef enum {
-	C1 = hz261,
-	CS1 = hz277,
-	D1 = hz293,
-	DS1 = hz311,
-	E1 = hz329,
-	F1 = hz349,
-	FS1 = hz369,
-	G1 = hz392,
-	GS1 = hz415,
-	A1 = hz440,
-	AS1 = hz466,
-	B1 = hz493,
-	C2 = hz523,
-	CS2 = hz554,
-	D2 = hz587,
-	DS2 = hz622,
-	E2 = hz659,
-	F2 = hz698,
-	FS2 = hz739,
-	G2 = hz783,
-	GS2 = hz830,
-	A2 = hz880,
-	AS2 = hz932,
-} IXJ_NOTE;
-
-typedef struct {
-	int tone_index;
-	int freq0;
-	int gain0;
-	int freq1;
-	int gain1;
-} IXJ_TONE;
-
-#define IXJCTL_INIT_TONE		_IOW ('q', 0xC9, IXJ_TONE *)
-
-/******************************************************************************
-*
-* The IXJCTL_TONE_CADENCE ioctl defines tone sequences used for various
-* Call Progress Tones (CPT).  This is accomplished by setting up an array of
-* IXJ_CADENCE_ELEMENT structures that sequentially define the states of
-* the tone sequence.  The tone_on_time and tone_off time are in
-* 250 microsecond intervals.  A pointer to this array is passed to the
-* driver as the ce element of an IXJ_CADENCE structure.  The elements_used
-* must be set to the number of IXJ_CADENCE_ELEMENTS in the array.  The
-* termination variable defines what to do at the end of a cadence, the
-* options are to play the cadence once and stop, to repeat the last
-* element of the cadence indefinatly, or to repeat the entire cadence
-* indefinatly.  The ce variable is a pointer to the array of IXJ_TONE
-* structures.  If the freq0 variable is non-zero, the tone table contents
-* for the tone_index are updated to the frequencies and gains defined.  It
-* should be noted that DTMF tones cannot be reassigned, so if DTMF tone
-* table indexs are used in a cadence the frequency and gain variables will
-* be ignored.
-*
-* If the array elements contain frequency parameters the driver will
-* initialize the needed tone table elements and begin playing the tone,
-* there is no preset limit on the number of elements in the cadence.  If
-* there is more than one frequency used in the cadence, sequential elements
-* of different frequencies MUST use different tone table indexes.  Only one
-* cadence can be played at a time.  It is possible to build complex
-* cadences with multiple frequencies using 2 tone table indexes by
-* alternating between them.
-*
-******************************************************************************/
-
-typedef struct {
-	int index;
-	int tone_on_time;
-	int tone_off_time;
-	int freq0;
-	int gain0;
-	int freq1;
-	int gain1;
-} IXJ_CADENCE_ELEMENT;
-
-typedef enum {
-	PLAY_ONCE,
-	REPEAT_LAST_ELEMENT,
-	REPEAT_ALL
-} IXJ_CADENCE_TERM;
-
-typedef struct {
-	int elements_used;
-	IXJ_CADENCE_TERM termination;
-	IXJ_CADENCE_ELEMENT *ce;
-} IXJ_CADENCE;
-
-#define IXJCTL_TONE_CADENCE		_IOW ('q', 0xCA, IXJ_CADENCE *)
-/******************************************************************************
-*
-* This group of IOCTLs deal with the playback settings of the DSP
-*
-******************************************************************************/
-
-#define IXJCTL_PLAY_CODEC               PHONE_PLAY_CODEC
-#define IXJCTL_PLAY_START               PHONE_PLAY_START
-#define IXJCTL_PLAY_STOP                PHONE_PLAY_STOP
-#define IXJCTL_PLAY_DEPTH		PHONE_PLAY_DEPTH
-#define IXJCTL_PLAY_VOLUME		PHONE_PLAY_VOLUME
-#define IXJCTL_PLAY_LEVEL		PHONE_PLAY_LEVEL
-
-/******************************************************************************
-*
-* This group of IOCTLs deal with the Acoustic Echo Cancellation settings
-* of the DSP
-*
-* Issueing the IXJCTL_AEC_START command with a value of AEC_OFF has the
-* same effect as IXJCTL_AEC_STOP.  This is to simplify slider bar
-* controls.  IXJCTL_AEC_GET_LEVEL returns the current setting of the AEC.
-******************************************************************************/
-#define IXJCTL_AEC_START		_IOW ('q', 0xCB, int)
-#define IXJCTL_AEC_STOP			_IO  ('q', 0xCC)
-#define IXJCTL_AEC_GET_LEVEL		_IO  ('q', 0xCD)
-
-#define AEC_OFF   0
-#define AEC_LOW   1
-#define AEC_MED   2
-#define AEC_HIGH  3
-/******************************************************************************
-*
-* Call Progress Tones, DTMF, etc.
-* IXJCTL_DTMF_OOB determines if dtmf signaling is sent as Out-Of-Band
-* only.  If you pass a 1, dtmf is suppressed from the audio stream.
-* Tone on and off times are in 250 microsecond intervals so
-* ioctl(ixj1, IXJCTL_SET_TONE_ON_TIME, 360);
-* will set the tone on time of board ixj1 to 360 * 250us = 90ms
-* the default values of tone on and off times is 840 or 210ms
-******************************************************************************/
-
-#define IXJCTL_DTMF_READY		PHONE_DTMF_READY
-#define IXJCTL_GET_DTMF                 PHONE_GET_DTMF
-#define IXJCTL_GET_DTMF_ASCII           PHONE_GET_DTMF_ASCII
-#define IXJCTL_DTMF_OOB			PHONE_DTMF_OOB
-#define IXJCTL_EXCEPTION		PHONE_EXCEPTION
-#define IXJCTL_PLAY_TONE		PHONE_PLAY_TONE
-#define IXJCTL_SET_TONE_ON_TIME		PHONE_SET_TONE_ON_TIME
-#define IXJCTL_SET_TONE_OFF_TIME	PHONE_SET_TONE_OFF_TIME
-#define IXJCTL_GET_TONE_ON_TIME		PHONE_GET_TONE_ON_TIME
-#define IXJCTL_GET_TONE_OFF_TIME	PHONE_GET_TONE_OFF_TIME
-#define IXJCTL_GET_TONE_STATE		PHONE_GET_TONE_STATE
-#define IXJCTL_BUSY			PHONE_BUSY
-#define IXJCTL_RINGBACK			PHONE_RINGBACK
-#define IXJCTL_DIALTONE			PHONE_DIALTONE
-#define IXJCTL_CPT_STOP			PHONE_CPT_STOP
-
-/******************************************************************************
-* LineJack specific IOCTLs
-*
-* The lsb 4 bits of the LED argument represent the state of each of the 4
-* LED's on the LineJack
-******************************************************************************/
-
-#define IXJCTL_SET_LED			_IOW ('q', 0xCE, int)
-#define IXJCTL_MIXER			_IOW ('q', 0xCF, int)
-
-/******************************************************************************
-* 
-* The master volume controls use attenuation with 32 levels from 0 to -62dB
-* with steps of 2dB each, the defines should be OR'ed together then sent
-* as the parameter to the mixer command to change the mixer settings.
-* 
-******************************************************************************/
-#define MIXER_MASTER_L		0x0100
-#define MIXER_MASTER_R		0x0200
-#define ATT00DB			0x00
-#define ATT02DB			0x01
-#define ATT04DB			0x02
-#define ATT06DB			0x03
-#define ATT08DB			0x04
-#define ATT10DB			0x05
-#define ATT12DB			0x06
-#define ATT14DB			0x07
-#define ATT16DB			0x08
-#define ATT18DB			0x09
-#define ATT20DB			0x0A
-#define ATT22DB			0x0B
-#define ATT24DB			0x0C
-#define ATT26DB			0x0D
-#define ATT28DB			0x0E
-#define ATT30DB			0x0F
-#define ATT32DB			0x10
-#define ATT34DB			0x11
-#define ATT36DB			0x12
-#define ATT38DB			0x13
-#define ATT40DB			0x14
-#define ATT42DB			0x15
-#define ATT44DB			0x16
-#define ATT46DB			0x17
-#define ATT48DB			0x18
-#define ATT50DB			0x19
-#define ATT52DB			0x1A
-#define ATT54DB			0x1B
-#define ATT56DB			0x1C
-#define ATT58DB			0x1D
-#define ATT60DB			0x1E
-#define ATT62DB			0x1F
-#define MASTER_MUTE		0x80
-
-/******************************************************************************
-* 
-* The input volume controls use gain with 32 levels from +12dB to -50dB
-* with steps of 2dB each, the defines should be OR'ed together then sent
-* as the parameter to the mixer command to change the mixer settings.
-* 
-******************************************************************************/
-#define MIXER_PORT_CD_L		0x0600
-#define MIXER_PORT_CD_R		0x0700
-#define MIXER_PORT_LINE_IN_L	0x0800
-#define MIXER_PORT_LINE_IN_R	0x0900
-#define MIXER_PORT_POTS_REC	0x0C00
-#define MIXER_PORT_MIC		0x0E00
-
-#define GAIN12DB		0x00
-#define GAIN10DB		0x01
-#define GAIN08DB		0x02
-#define GAIN06DB		0x03
-#define GAIN04DB		0x04
-#define GAIN02DB		0x05
-#define GAIN00DB		0x06
-#define GAIN_02DB		0x07
-#define GAIN_04DB		0x08
-#define GAIN_06DB		0x09
-#define GAIN_08DB		0x0A
-#define GAIN_10DB		0x0B
-#define GAIN_12DB		0x0C
-#define GAIN_14DB		0x0D
-#define GAIN_16DB		0x0E
-#define GAIN_18DB		0x0F
-#define GAIN_20DB		0x10
-#define GAIN_22DB		0x11
-#define GAIN_24DB		0x12
-#define GAIN_26DB		0x13
-#define GAIN_28DB		0x14
-#define GAIN_30DB		0x15
-#define GAIN_32DB		0x16
-#define GAIN_34DB		0x17
-#define GAIN_36DB		0x18
-#define GAIN_38DB		0x19
-#define GAIN_40DB		0x1A
-#define GAIN_42DB		0x1B
-#define GAIN_44DB		0x1C
-#define GAIN_46DB		0x1D
-#define GAIN_48DB		0x1E
-#define GAIN_50DB		0x1F
-#define INPUT_MUTE		0x80
-
-/******************************************************************************
-* 
-* The POTS volume control use attenuation with 8 levels from 0dB to -28dB
-* with steps of 4dB each, the defines should be OR'ed together then sent
-* as the parameter to the mixer command to change the mixer settings.
-* 
-******************************************************************************/
-#define MIXER_PORT_POTS_PLAY	0x0F00
-
-#define POTS_ATT_00DB		0x00
-#define POTS_ATT_04DB		0x01
-#define POTS_ATT_08DB		0x02
-#define POTS_ATT_12DB		0x03
-#define POTS_ATT_16DB		0x04
-#define POTS_ATT_20DB		0x05
-#define POTS_ATT_24DB		0x06
-#define POTS_ATT_28DB		0x07
-#define POTS_MUTE		0x80
-
-/******************************************************************************
-* 
-* The DAA controls the interface to the PSTN port.  The driver loads the
-* US coefficients by default, so if you live in a different country you
-* need to load the set for your countries phone system.
-* 
-******************************************************************************/
-#define IXJCTL_DAA_COEFF_SET		_IOW ('q', 0xD0, int)
-
-#define DAA_US 		1	//PITA 8kHz
-#define DAA_UK 		2	//ISAR34 8kHz
-#define DAA_FRANCE 	3	//
-#define DAA_GERMANY	4
-#define DAA_AUSTRALIA	5
-#define DAA_JAPAN	6
-
-/******************************************************************************
-* 
-* Use IXJCTL_PORT to set or query the port the card is set to.  If the
-* argument is set to PORT_QUERY, the return value of the ioctl will
-* indicate which port is currently in use, otherwise it will change the
-* port.
-* 
-******************************************************************************/
-#define IXJCTL_PORT			_IOW ('q', 0xD1, int)
-
-#define PORT_QUERY	0
-#define PORT_POTS	1
-#define PORT_PSTN	2
-#define PORT_SPEAKER	3
-#define PORT_HANDSET	4
-
-#define IXJCTL_PSTN_SET_STATE		PHONE_PSTN_SET_STATE
-#define IXJCTL_PSTN_GET_STATE		PHONE_PSTN_GET_STATE
-
-#define PSTN_ON_HOOK	0
-#define PSTN_RINGING	1
-#define PSTN_OFF_HOOK	2
-#define PSTN_PULSE_DIAL	3
-
-/******************************************************************************
-* 
-* The DAA Analog GAIN sets 2 parameters at one time, the receive gain (AGRR), 
-* and the transmit gain (AGX).  OR together the components and pass them
-* as the parameter to IXJCTL_DAA_AGAIN.  The default setting is both at 0dB.
-* 
-******************************************************************************/
-#define IXJCTL_DAA_AGAIN		_IOW ('q', 0xD2, int)
-
-#define AGRR00DB	0x00	// Analog gain in receive direction 0dB
-#define AGRR3_5DB	0x10	// Analog gain in receive direction 3.5dB
-#define AGRR06DB	0x30	// Analog gain in receive direction 6dB
-
-#define AGX00DB		0x00	// Analog gain in transmit direction 0dB
-#define AGX_6DB		0x04	// Analog gain in transmit direction -6dB
-#define AGX3_5DB	0x08	// Analog gain in transmit direction 3.5dB
-#define AGX_2_5B	0x0C	// Analog gain in transmit direction -2.5dB
-
-#define IXJCTL_PSTN_LINETEST		_IO  ('q', 0xD3)
-
-typedef struct {
-	char month[3];
-	char day[3];
-	char hour[3];
-	char min[3];
-	int numlen;
-	char number[11];
-	int namelen;
-	char name[80];
-} IXJ_CID;
-
-#define IXJCTL_CID			_IOR ('q', 0xD4, IXJ_CID *)
-/******************************************************************************
-* 
-* The wink duration is tunable with this ioctl.  The default wink duration  
-* is 320ms.  You do not need to use this ioctl if you do not require a
-* different wink duration.
-* 
-******************************************************************************/
-#define IXJCTL_WINK_DURATION		PHONE_WINK_DURATION
-
-/******************************************************************************
-* 
-* This ioctl will connect the POTS port to the PSTN port on the LineJACK
-* In order for this to work properly the port selection should be set to
-* the PSTN port with IXJCTL_PORT prior to calling this ioctl.  This will
-* enable conference calls between PSTN callers and network callers.
-* Passing a 1 to this ioctl enables the POTS<->PSTN connection while
-* passing a 0 turns it back off.
-* 
-******************************************************************************/
-#define IXJCTL_POTS_PSTN		_IOW ('q', 0xD5, int)
-
-/******************************************************************************
-*
-* IOCTLs added by request.
-*
-* IXJCTL_HZ sets the value your Linux kernel uses for HZ as defined in
-*           /usr/include/asm/param.h, this determines the fundamental
-*           frequency of the clock ticks on your Linux system.  The kernel
-*           must be rebuilt if you change this value, also all modules you
-*           use (except this one) must be recompiled.  The default value
-*           is 100, and you only need to use this IOCTL if you use some
-*           other value.
-*
-*
-* IXJCTL_RATE sets the number of times per second that the driver polls
-*             the DSP.  This value cannot be larger than HZ.  By
-*             increasing both of these values, you may be able to reduce
-*             latency because the max hang time that can exist between the
-*             driver and the DSP will be reduced.
-*
-******************************************************************************/
-
-#define IXJCTL_HZ                       _IOW ('q', 0xE0, int)
-#define IXJCTL_RATE                     _IOW ('q', 0xE1, int)
-#define IXJCTL_FRAMES_READ		_IOR ('q', 0xE2, unsigned long)
-#define IXJCTL_FRAMES_WRITTEN		_IOR ('q', 0xE3, unsigned long)
-#define IXJCTL_READ_WAIT		_IOR ('q', 0xE4, unsigned long)
-#define IXJCTL_WRITE_WAIT		_IOR ('q', 0xE5, unsigned long)
-#define IXJCTL_DRYBUFFER_READ		_IOR ('q', 0xE6, unsigned long)
-#define IXJCTL_DRYBUFFER_CLEAR		_IO  ('q', 0xE7)
-
-/******************************************************************************
-*
-* The intercom IOCTL's short the output from one card to the input of the
-* other and vice versa (actually done in the DSP read function).  It is only
-* necessary to execute the IOCTL on one card, but it is necessary to have
-* both devices open to be able to detect hook switch changes.  The record
-* codec and rate of each card must match the playback codec and rate of
-* the other card for this to work properly.
-*
-******************************************************************************/
-
-#define IXJCTL_INTERCOM_START 		_IOW ('q', 0xFD, int)
-#define IXJCTL_INTERCOM_STOP  		_IOW ('q', 0xFE, int)
diff -urN linux-2.2.14-pre16/fs/ncpfs/inode.c linux-2.2.14-pre17/fs/ncpfs/inode.c
--- linux-2.2.14-pre16/fs/ncpfs/inode.c	1999-05-14 12:43:13.000000000 -0700
+++ linux-2.2.14-pre17/fs/ncpfs/inode.c	2003-08-15 15:10:03.000000000 -0700
@@ -134,10 +134,16 @@
 	if ((inode->i_size)&&(inode->i_blksize)) {
 		inode->i_blocks = (inode->i_size-1)/(inode->i_blksize)+1;
 	}
-	/* TODO: times? I'm not sure... */
-	NCP_FINFO(inode)->DosDirNum = nwinfo->i.DosDirNum;
-	NCP_FINFO(inode)->dirEntNum = nwinfo->i.dirEntNum;
-	NCP_FINFO(inode)->volNumber = nwinfo->i.volNumber;
+
+	inode->i_mtime = ncp_date_dos2unix(le16_to_cpu(nwi->modifyTime),
+					   le16_to_cpu(nwi->modifyDate));
+	inode->i_ctime = ncp_date_dos2unix(le16_to_cpu(nwi->creationTime),
+					   le16_to_cpu(nwi->creationDate));
+	inode->i_atime = ncp_date_dos2unix(0, le16_to_cpu(nwi->lastAccessDate));
+
+	NCP_FINFO(inode)->DosDirNum = nwi->DosDirNum;
+	NCP_FINFO(inode)->dirEntNum = nwi->dirEntNum;
+	NCP_FINFO(inode)->volNumber = nwi->volNumber;
 }
 
 /*
diff -urN linux-2.2.14-pre16/fs/vfat/namei.c linux-2.2.14-pre17/fs/vfat/namei.c
--- linux-2.2.14-pre16/fs/vfat/namei.c	2003-08-15 15:10:01.000000000 -0700
+++ linux-2.2.14-pre17/fs/vfat/namei.c	2003-08-15 15:10:03.000000000 -0700
@@ -661,7 +661,7 @@
 		op = outname;
 		if (nls) {
 			for (i = 0, ip = name, op = outname, *outlen = 0;
-			     i < len && *outlen <= 260; i++, *outlen += 1)
+			     i < len && *outlen <= 260; *outlen += 1)
 			{
 				if (escape && (*ip == ':')) {
 					if (i > len - 4) return -EINVAL;
@@ -673,10 +673,12 @@
 					*op++ = (c1 << 4) + (c2 >> 2);
 					*op++ = ((c2 & 0x3) << 6) + c3;
 					ip += 4;
+					i += 4;
 				} else {
 					*op++ = nls->charset2uni[*ip].uni1;
 					*op++ = nls->charset2uni[*ip].uni2;
 					ip++;
+					i++;
 				}
 			}
 		} else {
diff -urN linux-2.2.14-pre16/include/linux/ixjuser.h linux-2.2.14-pre17/include/linux/ixjuser.h
--- linux-2.2.14-pre16/include/linux/ixjuser.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.2.14-pre17/include/linux/ixjuser.h	2003-08-15 15:10:03.000000000 -0700
@@ -0,0 +1,629 @@
+/*
+ *    ixjuser.h
+ *
+ *    User-space include file for the Internet PhoneJACK and
+ *    Internet LineJACK Telephony Cards.
+ *
+ *    (c) Copyright 1999 Quicknet Technologies, Inc.
+ *
+ *    This program is free software; you can redistribute it and/or
+ *    modify it under the terms of the GNU General Public License
+ *    as published by the Free Software Foundation; either version
+ *    2 of the License, or (at your option) any later version.
+ *
+ * Author:          Ed Okerson, <eokerson@quicknet.net>
+ *    
+ * Contributors:    Greg Herlein, <gherlein@quicknet.net>
+ *                  David W. Erhart, <derhart@quicknet.net>
+ *                  John Sellers, <jsellers@quicknet.net>
+ *                  Mike Preston, <mpreston@quicknet.net>
+ *
+ * More information about the hardware related to this driver can be found
+ * at our website:    http://www.quicknet.net
+ *
+ * Fixes:
+ */
+
+static char ixjuser_h_rcsid[] = "$Id: ixjuser.h,v 3.4 1999/12/16 22:18:36 root Exp root $";
+
+#include <linux/telephony.h>
+
+/***************************************************************************
+
+  If you use the IXJCTL_TESTRAM command, the card must be power
+  cycled to reset the SRAM values before futher use.
+
+***************************************************************************/
+#define IXJCTL_DSP_RESET 		_IO  ('q', 0xC0)
+
+#define IXJCTL_RING         PHONE_RING
+#define IXJCTL_HOOKSTATE    PHONE_HOOKSTATE
+#define IXJCTL_MAXRINGS			PHONE_MAXRINGS
+#define IXJCTL_RING_CADENCE	PHONE_RING_CADENCE
+#define IXJCTL_RING_START		PHONE_RING_START
+#define IXJCTL_RING_STOP		PHONE_RING_STOP
+
+#define IXJCTL_CARDTYPE			_IOR ('q', 0xC1, int)
+#define IXJCTL_SERIAL			  _IOR ('q', 0xC2, int)
+#define IXJCTL_DSP_TYPE     _IOR ('q', 0xC3, int)
+#define IXJCTL_DSP_VERSION  _IOR ('q', 0xC4, int)
+#define IXJCTL_DSP_IDLE			_IO  ('q', 0xC5)
+#define IXJCTL_TESTRAM			_IO  ('q', 0xC6)
+
+/******************************************************************************
+*
+* This group of IOCTLs deal with the record settings of the DSP
+*
+* The IXJCTL_REC_DEPTH command sets the internal buffer depth of the DSP.
+* Setting a lower depth reduces latency, but increases the demand of the
+* application to service the driver without frame loss.  The DSP has 480
+* bytes of physical buffer memory for the record channel so the true
+* maximum limit is determined by how many frames will fit in the buffer.
+*
+* 1 uncompressed (480 byte) 16-bit linear frame.
+* 2 uncompressed (240 byte) 8-bit A-law/mu-law frames.
+* 15 TrueSpeech 8.5 frames.
+* 20 TrueSpeech 6.3,5.3,4.8 or 4.1 frames.
+*
+* The default in the driver is currently set to 2 frames.
+*
+* The IXJCTL_REC_VOLUME and IXJCTL_PLAY_VOLUME commands both use a Q8
+* number as a parameter, 0x100 scales the signal by 1.0, 0x200 scales the
+* signal by 2.0, 0x80 scales the signal by 0.5.  No protection is given
+* against over-scaling, if the multiplication factor times the input
+* signal exceeds 16 bits, overflow distortion will occur.  The default
+* setting is 0x100 (1.0).
+*
+* The IXJCTL_REC_LEVEL returns the average signal level (not r.m.s.) on
+* the most recently recorded frame as a 16 bit value.
+******************************************************************************/
+
+#define IXJCTL_REC_CODEC                PHONE_REC_CODEC
+#define IXJCTL_REC_START                PHONE_REC_START
+#define IXJCTL_REC_STOP                 PHONE_REC_STOP
+#define IXJCTL_REC_DEPTH		PHONE_REC_DEPTH
+#define IXJCTL_FRAME			PHONE_FRAME
+#define IXJCTL_REC_VOLUME		PHONE_REC_VOLUME
+#define IXJCTL_REC_LEVEL		PHONE_REC_LEVEL
+
+typedef enum {
+	f300_640 = 4, f300_500, f1100, f350, f400, f480, f440, f620, f20_50,
+	f133_200, f300, f300_420, f330, f300_425, f330_440, f340, f350_400,
+	f350_440, f350_450, f360, f380_420, f392, f400_425, f400_440, f400_450,
+	f420, f425, f425_450, f425_475, f435, f440_450, f440_480, f445, f450,
+	f452, f475, f480_620, f494, f500, f520, f523, f525, f540_660, f587,
+	f590, f600, f660, f700, f740, f750, f750_1450, f770, f800, f816, f850,
+	f857_1645, f900, f900_1300, f935_1215, f941_1477, f942, f950, f950_1400,
+	f975, f1000, f1020, f1050, f1100_1750, f1140, f1200, f1209, f1330, f1336,
+	lf1366, f1380, f1400, f1477, f1600, f1633_1638, f1800, f1860
+} IXJ_FILTER_FREQ;
+
+typedef struct {
+	unsigned int filter;
+	IXJ_FILTER_FREQ freq;
+	char enable;
+} IXJ_FILTER;
+
+#define IXJCTL_SET_FILTER		_IOW ('q', 0xC7, IXJ_FILTER *)
+#define IXJCTL_GET_FILTER_HIST		_IOW ('q', 0xC8, int)
+/******************************************************************************
+*
+* This IOCTL allows you to reassign values in the tone index table.  The
+* tone table has 32 entries (0 - 31), but the driver only allows entries
+* 13 - 27 to be modified, entry 0 is reserved for silence and 1 - 12 are
+* the standard DTMF digits and 28 - 31 are the DTMF tones for A, B, C & D.
+* The positions used internally for Call Progress Tones are as follows:
+*    Dial Tone   - 25
+*    Ring Back   - 26
+*    Busy Signal - 27
+*
+* The freq values are calculated as:
+* freq = cos(2 * PI * frequency / 8000)
+*
+* The most commonly needed values are already calculated and listed in the
+* enum IXJ_TONE_FREQ.  Each tone index can have two frequencies with
+* different gains, if you are only using a single frequency set the unused
+* one to 0.
+*
+* The gain values range from 0 to 15 indicating +6dB to -24dB in 2dB
+* increments.
+*
+******************************************************************************/
+
+typedef enum {
+	hz20 = 0x7ffa,
+	hz50 = 0x7fe5,
+	hz133 = 0x7f4c,
+	hz200 = 0x7e6b,
+	hz261 = 0x7d50,		/* .63 C1  */
+	hz277 = 0x7cfa,		/* .18 CS1 */
+	hz293 = 0x7c9f,		/* .66 D1  */
+	hz300 = 0x7c75,
+	hz311 = 0x7c32,		/* .13 DS1 */
+	hz329 = 0x7bbf,		/* .63 E1  */
+	hz330 = 0x7bb8,
+	hz340 = 0x7b75,
+	hz349 = 0x7b37,		/* .23 F1  */
+	hz350 = 0x7b30,
+	hz360 = 0x7ae9,
+	hz369 = 0x7aa8,		/* .99 FS1 */
+	hz380 = 0x7a56,
+	hz392 = 0x79fa,		/* .00 G1  */
+	hz400 = 0x79bb,
+	hz415 = 0x7941,		/* .30 GS1 */
+	hz420 = 0x7918,
+	hz425 = 0x78ee,
+	hz435 = 0x7899,
+	hz440 = 0x786d,		/* .00 A1  */
+	hz445 = 0x7842,
+	hz450 = 0x7815,
+	hz452 = 0x7803,
+	hz466 = 0x7784,		/* .16 AS1 */
+	hz475 = 0x7731,
+	hz480 = 0x7701,
+	hz493 = 0x7685,		/* .88 B1  */
+	hz494 = 0x767b,
+	hz500 = 0x7640,
+	hz520 = 0x7578,
+	hz523 = 0x7559,		/* .25 C2  */
+	hz525 = 0x7544,
+	hz540 = 0x74a7,
+	hz554 = 0x7411,		/* .37 CS2 */
+	hz587 = 0x72a1,		/* .33 D2  */
+	hz590 = 0x727f,
+	hz600 = 0x720b,
+	hz620 = 0x711e,
+	hz622 = 0x7106,		/* .25 DS2 */
+	hz659 = 0x6f3b,		/* .26 E2  */
+	hz660 = 0x6f2e,
+	hz698 = 0x6d3d,		/* .46 F2  */
+	hz700 = 0x6d22,
+	hz739 = 0x6b09,		/* .99 FS2 */
+	hz740 = 0x6afa,
+	hz750 = 0x6a6c,
+	hz770 = 0x694b,
+	hz783 = 0x688b,		/* .99 G2  */
+	hz800 = 0x678d,
+	hz816 = 0x6698,
+	hz830 = 0x65bf,		/* .61 GS2 */
+	hz850 = 0x6484,
+	hz857 = 0x6414,
+	hz880 = 0x629f,		/* .00 A2  */
+	hz900 = 0x6154,
+	hz932 = 0x5f35,		/* .33 AS2 */
+	hz935 = 0x5f01,
+	hz941 = 0x5e9a,
+	hz942 = 0x5e88,
+	hz950 = 0x5dfd,
+	hz975 = 0x5c44,
+	hz1000 = 0x5a81,
+	hz1020 = 0x5912,
+	hz1050 = 0x56e2,
+	hz1100 = 0x5320,
+	hz1140 = 0x5007,
+	hz1200 = 0x4b3b,
+	hz1209 = 0x4a80,
+	hz1215 = 0x4a02,
+	hz1250 = 0x471c,
+	hz1300 = 0x42e0,
+	hz1330 = 0x4049,
+	hz1336 = 0x3fc4,
+	hz1366 = 0x3d22,
+	hz1380 = 0x3be4,
+	hz1400 = 0x3a1b,
+	hz1450 = 0x3596,
+	hz1477 = 0x331c,
+	hz1500 = 0x30fb,
+	hz1600 = 0x278d,
+	hz1633 = 0x2462,
+	hz1638 = 0x23e7,
+	hz1645 = 0x233a,
+	hz1750 = 0x18f8,
+	hz1800 = 0x1405,
+	hz1860 = 0xe0b,
+	hz2100 = 0xf5f6,
+	hz2450 = 0xd3b3
+} IXJ_FREQ;
+
+typedef enum {
+	C1 = hz261,
+	CS1 = hz277,
+	D1 = hz293,
+	DS1 = hz311,
+	E1 = hz329,
+	F1 = hz349,
+	FS1 = hz369,
+	G1 = hz392,
+	GS1 = hz415,
+	A1 = hz440,
+	AS1 = hz466,
+	B1 = hz493,
+	C2 = hz523,
+	CS2 = hz554,
+	D2 = hz587,
+	DS2 = hz622,
+	E2 = hz659,
+	F2 = hz698,
+	FS2 = hz739,
+	G2 = hz783,
+	GS2 = hz830,
+	A2 = hz880,
+	AS2 = hz932,
+} IXJ_NOTE;
+
+typedef struct {
+	int tone_index;
+	int freq0;
+	int gain0;
+	int freq1;
+	int gain1;
+} IXJ_TONE;
+
+#define IXJCTL_INIT_TONE		_IOW ('q', 0xC9, IXJ_TONE *)
+
+/******************************************************************************
+*
+* The IXJCTL_TONE_CADENCE ioctl defines tone sequences used for various
+* Call Progress Tones (CPT).  This is accomplished by setting up an array of
+* IXJ_CADENCE_ELEMENT structures that sequentially define the states of
+* the tone sequence.  The tone_on_time and tone_off time are in
+* 250 microsecond intervals.  A pointer to this array is passed to the
+* driver as the ce element of an IXJ_CADENCE structure.  The elements_used
+* must be set to the number of IXJ_CADENCE_ELEMENTS in the array.  The
+* termination variable defines what to do at the end of a cadence, the
+* options are to play the cadence once and stop, to repeat the last
+* element of the cadence indefinatly, or to repeat the entire cadence
+* indefinatly.  The ce variable is a pointer to the array of IXJ_TONE
+* structures.  If the freq0 variable is non-zero, the tone table contents
+* for the tone_index are updated to the frequencies and gains defined.  It
+* should be noted that DTMF tones cannot be reassigned, so if DTMF tone
+* table indexs are used in a cadence the frequency and gain variables will
+* be ignored.
+*
+* If the array elements contain frequency parameters the driver will
+* initialize the needed tone table elements and begin playing the tone,
+* there is no preset limit on the number of elements in the cadence.  If
+* there is more than one frequency used in the cadence, sequential elements
+* of different frequencies MUST use different tone table indexes.  Only one
+* cadence can be played at a time.  It is possible to build complex
+* cadences with multiple frequencies using 2 tone table indexes by
+* alternating between them.
+*
+******************************************************************************/
+
+typedef struct {
+	int index;
+	int tone_on_time;
+	int tone_off_time;
+	int freq0;
+	int gain0;
+	int freq1;
+	int gain1;
+} IXJ_CADENCE_ELEMENT;
+
+typedef enum {
+	PLAY_ONCE,
+	REPEAT_LAST_ELEMENT,
+	REPEAT_ALL
+} IXJ_CADENCE_TERM;
+
+typedef struct {
+	int elements_used;
+	IXJ_CADENCE_TERM termination;
+	IXJ_CADENCE_ELEMENT *ce;
+} IXJ_CADENCE;
+
+#define IXJCTL_TONE_CADENCE		_IOW ('q', 0xCA, IXJ_CADENCE *)
+/******************************************************************************
+*
+* This group of IOCTLs deal with the playback settings of the DSP
+*
+******************************************************************************/
+
+#define IXJCTL_PLAY_CODEC               PHONE_PLAY_CODEC
+#define IXJCTL_PLAY_START               PHONE_PLAY_START
+#define IXJCTL_PLAY_STOP                PHONE_PLAY_STOP
+#define IXJCTL_PLAY_DEPTH		PHONE_PLAY_DEPTH
+#define IXJCTL_PLAY_VOLUME		PHONE_PLAY_VOLUME
+#define IXJCTL_PLAY_LEVEL		PHONE_PLAY_LEVEL
+
+/******************************************************************************
+*
+* This group of IOCTLs deal with the Acoustic Echo Cancellation settings
+* of the DSP
+*
+* Issueing the IXJCTL_AEC_START command with a value of AEC_OFF has the
+* same effect as IXJCTL_AEC_STOP.  This is to simplify slider bar
+* controls.  IXJCTL_AEC_GET_LEVEL returns the current setting of the AEC.
+******************************************************************************/
+#define IXJCTL_AEC_START		_IOW ('q', 0xCB, int)
+#define IXJCTL_AEC_STOP			_IO  ('q', 0xCC)
+#define IXJCTL_AEC_GET_LEVEL		_IO  ('q', 0xCD)
+
+#define AEC_OFF   0
+#define AEC_LOW   1
+#define AEC_MED   2
+#define AEC_HIGH  3
+/******************************************************************************
+*
+* Call Progress Tones, DTMF, etc.
+* IXJCTL_DTMF_OOB determines if dtmf signaling is sent as Out-Of-Band
+* only.  If you pass a 1, dtmf is suppressed from the audio stream.
+* Tone on and off times are in 250 microsecond intervals so
+* ioctl(ixj1, IXJCTL_SET_TONE_ON_TIME, 360);
+* will set the tone on time of board ixj1 to 360 * 250us = 90ms
+* the default values of tone on and off times is 840 or 210ms
+******************************************************************************/
+
+#define IXJCTL_DTMF_READY		PHONE_DTMF_READY
+#define IXJCTL_GET_DTMF                 PHONE_GET_DTMF
+#define IXJCTL_GET_DTMF_ASCII           PHONE_GET_DTMF_ASCII
+#define IXJCTL_DTMF_OOB			PHONE_DTMF_OOB
+#define IXJCTL_EXCEPTION		PHONE_EXCEPTION
+#define IXJCTL_PLAY_TONE		PHONE_PLAY_TONE
+#define IXJCTL_SET_TONE_ON_TIME		PHONE_SET_TONE_ON_TIME
+#define IXJCTL_SET_TONE_OFF_TIME	PHONE_SET_TONE_OFF_TIME
+#define IXJCTL_GET_TONE_ON_TIME		PHONE_GET_TONE_ON_TIME
+#define IXJCTL_GET_TONE_OFF_TIME	PHONE_GET_TONE_OFF_TIME
+#define IXJCTL_GET_TONE_STATE		PHONE_GET_TONE_STATE
+#define IXJCTL_BUSY			PHONE_BUSY
+#define IXJCTL_RINGBACK			PHONE_RINGBACK
+#define IXJCTL_DIALTONE			PHONE_DIALTONE
+#define IXJCTL_CPT_STOP			PHONE_CPT_STOP
+
+/******************************************************************************
+* LineJack specific IOCTLs
+*
+* The lsb 4 bits of the LED argument represent the state of each of the 4
+* LED's on the LineJack
+******************************************************************************/
+
+#define IXJCTL_SET_LED			_IOW ('q', 0xCE, int)
+#define IXJCTL_MIXER			_IOW ('q', 0xCF, int)
+
+/******************************************************************************
+* 
+* The master volume controls use attenuation with 32 levels from 0 to -62dB
+* with steps of 2dB each, the defines should be OR'ed together then sent
+* as the parameter to the mixer command to change the mixer settings.
+* 
+******************************************************************************/
+#define MIXER_MASTER_L		0x0100
+#define MIXER_MASTER_R		0x0200
+#define ATT00DB			0x00
+#define ATT02DB			0x01
+#define ATT04DB			0x02
+#define ATT06DB			0x03
+#define ATT08DB			0x04
+#define ATT10DB			0x05
+#define ATT12DB			0x06
+#define ATT14DB			0x07
+#define ATT16DB			0x08
+#define ATT18DB			0x09
+#define ATT20DB			0x0A
+#define ATT22DB			0x0B
+#define ATT24DB			0x0C
+#define ATT26DB			0x0D
+#define ATT28DB			0x0E
+#define ATT30DB			0x0F
+#define ATT32DB			0x10
+#define ATT34DB			0x11
+#define ATT36DB			0x12
+#define ATT38DB			0x13
+#define ATT40DB			0x14
+#define ATT42DB			0x15
+#define ATT44DB			0x16
+#define ATT46DB			0x17
+#define ATT48DB			0x18
+#define ATT50DB			0x19
+#define ATT52DB			0x1A
+#define ATT54DB			0x1B
+#define ATT56DB			0x1C
+#define ATT58DB			0x1D
+#define ATT60DB			0x1E
+#define ATT62DB			0x1F
+#define MASTER_MUTE		0x80
+
+/******************************************************************************
+* 
+* The input volume controls use gain with 32 levels from +12dB to -50dB
+* with steps of 2dB each, the defines should be OR'ed together then sent
+* as the parameter to the mixer command to change the mixer settings.
+* 
+******************************************************************************/
+#define MIXER_PORT_CD_L		0x0600
+#define MIXER_PORT_CD_R		0x0700
+#define MIXER_PORT_LINE_IN_L	0x0800
+#define MIXER_PORT_LINE_IN_R	0x0900
+#define MIXER_PORT_POTS_REC	0x0C00
+#define MIXER_PORT_MIC		0x0E00
+
+#define GAIN12DB		0x00
+#define GAIN10DB		0x01
+#define GAIN08DB		0x02
+#define GAIN06DB		0x03
+#define GAIN04DB		0x04
+#define GAIN02DB		0x05
+#define GAIN00DB		0x06
+#define GAIN_02DB		0x07
+#define GAIN_04DB		0x08
+#define GAIN_06DB		0x09
+#define GAIN_08DB		0x0A
+#define GAIN_10DB		0x0B
+#define GAIN_12DB		0x0C
+#define GAIN_14DB		0x0D
+#define GAIN_16DB		0x0E
+#define GAIN_18DB		0x0F
+#define GAIN_20DB		0x10
+#define GAIN_22DB		0x11
+#define GAIN_24DB		0x12
+#define GAIN_26DB		0x13
+#define GAIN_28DB		0x14
+#define GAIN_30DB		0x15
+#define GAIN_32DB		0x16
+#define GAIN_34DB		0x17
+#define GAIN_36DB		0x18
+#define GAIN_38DB		0x19
+#define GAIN_40DB		0x1A
+#define GAIN_42DB		0x1B
+#define GAIN_44DB		0x1C
+#define GAIN_46DB		0x1D
+#define GAIN_48DB		0x1E
+#define GAIN_50DB		0x1F
+#define INPUT_MUTE		0x80
+
+/******************************************************************************
+* 
+* The POTS volume control use attenuation with 8 levels from 0dB to -28dB
+* with steps of 4dB each, the defines should be OR'ed together then sent
+* as the parameter to the mixer command to change the mixer settings.
+* 
+******************************************************************************/
+#define MIXER_PORT_POTS_PLAY	0x0F00
+
+#define POTS_ATT_00DB		0x00
+#define POTS_ATT_04DB		0x01
+#define POTS_ATT_08DB		0x02
+#define POTS_ATT_12DB		0x03
+#define POTS_ATT_16DB		0x04
+#define POTS_ATT_20DB		0x05
+#define POTS_ATT_24DB		0x06
+#define POTS_ATT_28DB		0x07
+#define POTS_MUTE		0x80
+
+/******************************************************************************
+* 
+* The DAA controls the interface to the PSTN port.  The driver loads the
+* US coefficients by default, so if you live in a different country you
+* need to load the set for your countries phone system.
+* 
+******************************************************************************/
+#define IXJCTL_DAA_COEFF_SET		_IOW ('q', 0xD0, int)
+
+#define DAA_US 		1	//PITA 8kHz
+#define DAA_UK 		2	//ISAR34 8kHz
+#define DAA_FRANCE 	3	//
+#define DAA_GERMANY	4
+#define DAA_AUSTRALIA	5
+#define DAA_JAPAN	6
+
+/******************************************************************************
+* 
+* Use IXJCTL_PORT to set or query the port the card is set to.  If the
+* argument is set to PORT_QUERY, the return value of the ioctl will
+* indicate which port is currently in use, otherwise it will change the
+* port.
+* 
+******************************************************************************/
+#define IXJCTL_PORT			_IOW ('q', 0xD1, int)
+
+#define PORT_QUERY	0
+#define PORT_POTS	1
+#define PORT_PSTN	2
+#define PORT_SPEAKER	3
+#define PORT_HANDSET	4
+
+#define IXJCTL_PSTN_SET_STATE		PHONE_PSTN_SET_STATE
+#define IXJCTL_PSTN_GET_STATE		PHONE_PSTN_GET_STATE
+
+#define PSTN_ON_HOOK	0
+#define PSTN_RINGING	1
+#define PSTN_OFF_HOOK	2
+#define PSTN_PULSE_DIAL	3
+
+/******************************************************************************
+* 
+* The DAA Analog GAIN sets 2 parameters at one time, the receive gain (AGRR), 
+* and the transmit gain (AGX).  OR together the components and pass them
+* as the parameter to IXJCTL_DAA_AGAIN.  The default setting is both at 0dB.
+* 
+******************************************************************************/
+#define IXJCTL_DAA_AGAIN		_IOW ('q', 0xD2, int)
+
+#define AGRR00DB	0x00	// Analog gain in receive direction 0dB
+#define AGRR3_5DB	0x10	// Analog gain in receive direction 3.5dB
+#define AGRR06DB	0x30	// Analog gain in receive direction 6dB
+
+#define AGX00DB		0x00	// Analog gain in transmit direction 0dB
+#define AGX_6DB		0x04	// Analog gain in transmit direction -6dB
+#define AGX3_5DB	0x08	// Analog gain in transmit direction 3.5dB
+#define AGX_2_5B	0x0C	// Analog gain in transmit direction -2.5dB
+
+#define IXJCTL_PSTN_LINETEST		_IO  ('q', 0xD3)
+
+typedef struct {
+	char month[3];
+	char day[3];
+	char hour[3];
+	char min[3];
+	int numlen;
+	char number[11];
+	int namelen;
+	char name[80];
+} IXJ_CID;
+
+#define IXJCTL_CID			_IOR ('q', 0xD4, IXJ_CID *)
+/******************************************************************************
+* 
+* The wink duration is tunable with this ioctl.  The default wink duration  
+* is 320ms.  You do not need to use this ioctl if you do not require a
+* different wink duration.
+* 
+******************************************************************************/
+#define IXJCTL_WINK_DURATION		PHONE_WINK_DURATION
+
+/******************************************************************************
+* 
+* This ioctl will connect the POTS port to the PSTN port on the LineJACK
+* In order for this to work properly the port selection should be set to
+* the PSTN port with IXJCTL_PORT prior to calling this ioctl.  This will
+* enable conference calls between PSTN callers and network callers.
+* Passing a 1 to this ioctl enables the POTS<->PSTN connection while
+* passing a 0 turns it back off.
+* 
+******************************************************************************/
+#define IXJCTL_POTS_PSTN		_IOW ('q', 0xD5, int)
+
+/******************************************************************************
+*
+* IOCTLs added by request.
+*
+* IXJCTL_HZ sets the value your Linux kernel uses for HZ as defined in
+*           /usr/include/asm/param.h, this determines the fundamental
+*           frequency of the clock ticks on your Linux system.  The kernel
+*           must be rebuilt if you change this value, also all modules you
+*           use (except this one) must be recompiled.  The default value
+*           is 100, and you only need to use this IOCTL if you use some
+*           other value.
+*
+*
+* IXJCTL_RATE sets the number of times per second that the driver polls
+*             the DSP.  This value cannot be larger than HZ.  By
+*             increasing both of these values, you may be able to reduce
+*             latency because the max hang time that can exist between the
+*             driver and the DSP will be reduced.
+*
+******************************************************************************/
+
+#define IXJCTL_HZ                       _IOW ('q', 0xE0, int)
+#define IXJCTL_RATE                     _IOW ('q', 0xE1, int)
+#define IXJCTL_FRAMES_READ		_IOR ('q', 0xE2, unsigned long)
+#define IXJCTL_FRAMES_WRITTEN		_IOR ('q', 0xE3, unsigned long)
+#define IXJCTL_READ_WAIT		_IOR ('q', 0xE4, unsigned long)
+#define IXJCTL_WRITE_WAIT		_IOR ('q', 0xE5, unsigned long)
+#define IXJCTL_DRYBUFFER_READ		_IOR ('q', 0xE6, unsigned long)
+#define IXJCTL_DRYBUFFER_CLEAR		_IO  ('q', 0xE7)
+
+/******************************************************************************
+*
+* The intercom IOCTL's short the output from one card to the input of the
+* other and vice versa (actually done in the DSP read function).  It is only
+* necessary to execute the IOCTL on one card, but it is necessary to have
+* both devices open to be able to detect hook switch changes.  The record
+* codec and rate of each card must match the playback codec and rate of
+* the other card for this to work properly.
+*
+******************************************************************************/
+
+#define IXJCTL_INTERCOM_START 		_IOW ('q', 0xFD, int)
+#define IXJCTL_INTERCOM_STOP  		_IOW ('q', 0xFE, int)
diff -urN linux-2.2.14-pre16/include/linux/tty.h linux-2.2.14-pre17/include/linux/tty.h
--- linux-2.2.14-pre16/include/linux/tty.h	1999-10-19 17:14:02.000000000 -0700
+++ linux-2.2.14-pre17/include/linux/tty.h	2003-08-15 15:10:03.000000000 -0700
@@ -348,6 +348,8 @@
 extern int lp_init(void);
 extern int pty_init(void);
 extern int tty_init(void);
+extern int mxser_init(void);
+extern int moxa_init(void);
 extern int ip2_init(void);
 extern int pcxe_init(void);
 extern int pc_init(void);
diff -urN linux-2.2.14-pre16/kernel/signal.c linux-2.2.14-pre17/kernel/signal.c
--- linux-2.2.14-pre16/kernel/signal.c	2003-08-15 15:10:01.000000000 -0700
+++ linux-2.2.14-pre17/kernel/signal.c	2003-08-15 15:10:03.000000000 -0700
@@ -680,7 +680,8 @@
 			break;
 		}
 
-		current->blocked = new_set;
+		if (!error)
+		    current->blocked = new_set;
 		recalc_sigpending(current);
 		spin_unlock_irq(&current->sigmask_lock);
 		if (error)
diff -urN linux-2.2.14-pre16/Makefile linux-2.2.14-pre17/Makefile
--- linux-2.2.14-pre16/Makefile	2003-08-15 15:10:00.000000000 -0700
+++ linux-2.2.14-pre17/Makefile	2003-08-15 15:10:02.000000000 -0700
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 2
 SUBLEVEL = 14
-EXTRAVERSION = pre16
+EXTRAVERSION = pre17
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
 
diff -urN linux-2.2.14-pre16/net/bridge/br.c linux-2.2.14-pre17/net/bridge/br.c
--- linux-2.2.14-pre16/net/bridge/br.c	2003-08-15 15:10:01.000000000 -0700
+++ linux-2.2.14-pre17/net/bridge/br.c	2003-08-15 15:10:03.000000000 -0700
@@ -88,6 +88,7 @@
 #include <linux/rtnetlink.h>
 #include <net/br.h>
 #include <linux/proc_fs.h>
+#include <linux/delay.h>
 
 #ifndef min
 #define min(a, b) (((a) <= (b)) ? (a) : (b))
@@ -2438,65 +2439,63 @@
  
 __initfunc(int brg_probe(struct device *dev))
 {
-  unsigned int bogomips;
-  struct timeval utime;
+	unsigned int bogomips;
+	struct timeval utime;
 
-  printk(KERN_INFO "%s: network interface for Ethernet Bridge 007/NET4.0\n", dev->name);
+	printk(KERN_INFO "%s: network interface for Ethernet Bridge 007/NET4.0\n", dev->name);
 
-  /*
-   *	Initialize the device structure.
-   */
+	/*
+	 *	Initialize the device structure.
+	 */
   
-  dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
-  if (dev->priv == NULL)
-    return -ENOMEM;
-  memset(dev->priv, 0, sizeof(struct net_local));
-
-  /* Set up MAC address based on BogoMIPs figure for first CPU and time
-   */ 
-  bogomips = (boot_cpu_data.loops_per_sec+2500)/500000 ;
-  get_fast_time(&utime);
-
-  /* Ummmm....  YES! */
-  dev->dev_addr[0] = '\xFE';
-  dev->dev_addr[1] = '\xFD';
-  dev->dev_addr[2] = (bridge_info.instance & 0x0F) << 4;
-  dev->dev_addr[2] |= ((utime.tv_sec & 0x000F0000) >> 16);
-  dev->dev_addr[3] = bogomips & 0xFF;
-  dev->dev_addr[4] = (utime.tv_sec & 0x0000FF00) >> 8;
-  dev->dev_addr[5] = (utime.tv_sec & 0x000000FF);
+	dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
+	if (dev->priv == NULL)
+		return -ENOMEM;
+	memset(dev->priv, 0, sizeof(struct net_local));
+
+	/* Set up MAC address based on BogoMIPs figure for first CPU and time
+	 */ 
+	bogomips = (loops_per_sec+2500)/500000 ;
+	get_fast_time(&utime);
+
+	/* Ummmm....  YES! */
+	dev->dev_addr[0] = '\xFE';
+	dev->dev_addr[1] = '\xFD';
+	dev->dev_addr[2] = (bridge_info.instance & 0x0F) << 4;
+	dev->dev_addr[2] |= ((utime.tv_sec & 0x000F0000) >> 16);
+	dev->dev_addr[3] = bogomips & 0xFF;
+	dev->dev_addr[4] = (utime.tv_sec & 0x0000FF00) >> 8;
+	dev->dev_addr[5] = (utime.tv_sec & 0x000000FF);
   
-  printk(KERN_INFO "%s: generated MAC address %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n", 
-	 dev->name,
-	 dev->dev_addr[0],
-	 dev->dev_addr[1],
-	 dev->dev_addr[2],
-	 dev->dev_addr[3],
-	 dev->dev_addr[4],
-	 dev->dev_addr[5]);
+	printk(KERN_INFO "%s: generated MAC address %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n", 
+		dev->name,
+		dev->dev_addr[0],
+		dev->dev_addr[1],
+		dev->dev_addr[2],
+		dev->dev_addr[3],
+		dev->dev_addr[4],
+		dev->dev_addr[5]);
 
   
-  printk(KERN_INFO "%s: attached to bridge instance %lu\n", dev->name, dev->base_addr);
-
-  /*
-   *	The brg specific entries in the device structure.
-   */
-
-  dev->open = brg_open;
-  dev->hard_start_xmit = brg_start_xmit;
-  dev->stop = brg_close;
-  dev->get_stats = brg_get_stats;
-  dev->set_multicast_list = brg_set_multicast_list;
+	printk(KERN_INFO "%s: attached to bridge instance %lu\n", dev->name, dev->base_addr);
 
-  /*
-   *	Setup the generic properties
-   */
+	/*
+	 *	The brg specific entries in the device structure.
+	 */
 
-  ether_setup(dev);
+	dev->open = brg_open;
+	dev->hard_start_xmit = brg_start_xmit;
+	dev->stop = brg_close;
+	dev->get_stats = brg_get_stats;
+	dev->set_multicast_list = brg_set_multicast_list;
 
-  dev->tx_queue_len = 0;
+	/*
+	 *	Setup the generic properties
+	 */
 
-  return 0;
+	ether_setup(dev);
+	dev->tx_queue_len = 0;
+	return 0;
 }
 
 /*
diff -urN linux-2.2.14-pre16/net/unix/sysctl_net_unix.c linux-2.2.14-pre17/net/unix/sysctl_net_unix.c
--- linux-2.2.14-pre16/net/unix/sysctl_net_unix.c	1999-03-21 07:22:00.000000000 -0800
+++ linux-2.2.14-pre17/net/unix/sysctl_net_unix.c	2003-08-15 15:10:03.000000000 -0700
@@ -30,7 +30,7 @@
 	 &proc_dointvec_jiffies},
 	{NET_UNIX_MAX_DGRAM_QLEN, "max_dgram_qlen",
 	&sysctl_unix_max_dgram_qlen, sizeof(int), 0600, NULL, 
-	 &proc_dointvec_jiffies},
+	 &proc_dointvec},
 	{0}
 };
 
