linux-cvs-patches
[Top] [All Lists]

CVS Update@linux-mips.org: linux

To: linux-cvs-patches@linux-mips.org
Subject: CVS Update@linux-mips.org: linux
From: ralf@linux-mips.org
Date: Fri, 23 Sep 2005 21:41:36 +0100
Reply-to: linux-mips@linux-mips.org
Sender: linux-cvs-patches-bounce@linux-mips.org
CVSROOT:        /home/cvs
Module name:    linux
Changes by:     ralf@ftp.linux-mips.org 05/09/23 21:41:30

Modified files:
        .              : Tag: linux_2_4 MAINTAINERS Makefile 
        Documentation  : Tag: linux_2_4 Configure.help cciss.txt 
        Documentation/crypto: Tag: linux_2_4 api-intro.txt 
        Documentation/networking: Tag: linux_2_4 vortex.txt 
        arch/alpha/kernel: Tag: linux_2_4 Makefile 
        arch/i386/kernel: Tag: linux_2_4 apm.c pci-irq.c process.c 
                          traps.c 
        arch/ia64/ia32 : Tag: linux_2_4 sys_ia32.c 
        arch/ia64/mm   : Tag: linux_2_4 fault.c 
        arch/ppc/boot/lib: Tag: linux_2_4 zlib.c 
        arch/ppc/kernel: Tag: linux_2_4 time.c 
        arch/ppc64/boot: Tag: linux_2_4 zlib.c 
        arch/ppc64/kernel: Tag: linux_2_4 ioctl32.c 
        arch/sparc64/kernel: Tag: linux_2_4 ioctl32.c sparc64_ksyms.c 
                             sys_sparc32.c 
        arch/sparc64/solaris: Tag: linux_2_4 socket.c 
        arch/x86_64/ia32: Tag: linux_2_4 ia32_ioctl.c sys_ia32.c 
        arch/x86_64/kernel: Tag: linux_2_4 io_apic.c pci-gart.c 
                            process.c ptrace.c setup.c traps.c 
        crypto         : Tag: linux_2_4 tcrypt.c tcrypt.h tea.c 
        drivers/block  : Tag: linux_2_4 cciss.c 
        drivers/bluetooth: Tag: linux_2_4 bfusb.c hci_usb.c 
        drivers/char   : Tag: linux_2_4 cyclades.c esp.c isicom.c 
                         mxser.c riscom8.c serial.c specialix.c 
        drivers/md     : Tag: linux_2_4 md.c 
        drivers/scsi   : Tag: linux_2_4 ahci.c ata_piix.c libata-core.c 
                         libata-scsi.c libata.h megaraid2.c megaraid2.h 
                         sata_nv.c sata_promise.c sata_qstor.c 
                         sata_sil.c sata_sis.c sata_svw.c sata_sx4.c 
                         sata_uli.c sata_via.c sata_vsc.c 
        drivers/sound  : Tag: linux_2_4 i810_audio.c 
        drivers/usb    : Tag: linux_2_4 printer.c 
        drivers/usb/gadget: Tag: linux_2_4 file_storage.c 
        drivers/usb/serial: Tag: linux_2_4 ftdi_sio.c ftdi_sio.h 
        fs             : Tag: linux_2_4 buffer.c inode.c 
        fs/isofs       : Tag: linux_2_4 compress.c inode.c 
        fs/nfs         : Tag: linux_2_4 nfs2xdr.c nfs3xdr.c 
        fs/nfsd        : Tag: linux_2_4 vfs.c 
        include/asm-i386: Tag: linux_2_4 system.h 
        include/asm-sparc64: Tag: linux_2_4 uaccess.h 
        include/asm-x86_64: Tag: linux_2_4 desc.h pci.h processor.h 
        include/linux  : Tag: linux_2_4 ata.h libata-compat.h libata.h 
                         pci_ids.h zlib.h 
        include/linux/netfilter_ipv4: Tag: linux_2_4 ip_nat_rule.h 
                                      ip_tables.h 
        include/net    : Tag: linux_2_4 ip6_fib.h ip6_route.h 
        lib            : Tag: linux_2_4 inflate.c rbtree.c 
        net/ipv4       : Tag: linux_2_4 inetpeer.c 
        net/ipv4/ipvs  : Tag: linux_2_4 ip_vs_conn.c 
        net/ipv4/netfilter: Tag: linux_2_4 ip_nat_proto_icmp.c 
                            ip_nat_proto_tcp.c ip_nat_proto_udp.c 
                            ip_nat_rule.c ip_nat_standalone.c ip_queue.c 
                            ipt_unclean.c 
        net/ipv6       : Tag: linux_2_4 addrconf.c ip6_fib.c mcast.c 
                         ndisc.c route.c 
        net/ipv6/netfilter: Tag: linux_2_4 ip6_queue.c ip6t_LOG.c 
        net/netlink    : Tag: linux_2_4 af_netlink.c 
Added files:
        drivers/char   : Tag: linux_2_4 serial.c.orig 
Removed files:
        arch/mips      : Tag: linux_2_4 .gdbinit 
        drivers/sound  : Tag: linux_2_4 .indent.pro .version 

Log message:
        Merge with Linux 2.4.32-rc1.

diff -urN linux/MAINTAINERS linux/MAINTAINERS
--- linux/MAINTAINERS   2005/05/05 13:43:41     1.76.2.34
+++ linux/MAINTAINERS   2005/09/23 20:41:15     1.76.2.35
@@ -116,7 +116,7 @@
 8169 10/100/1000 GIGABIT ETHERNET DRIVER
 P:     Francois Romieu
 M:     romieu@fr.zoreil.com
-L:     netdev@oss.sgi.com
+L:     netdev@vger.kernel.org
 S:     Maintained
 
 8250/16?50 (AND CLONE UARTS) SERIAL DRIVER
@@ -820,7 +820,7 @@
 I2C SUBSYSTEM
 P:     Jean Delvare
 M:     khali@linux-fr.org
-L:     sensors@stimpy.netroedge.com
+L:     lm-sensors@lm-sensors.org
 W:     http://www.lm-sensors.nu/
 S:     Maintained
 
@@ -1186,7 +1186,7 @@
 P:     Manish Lachwani
 M:     Manish_Lachwani@pmc-sierra.com
 L:     linux-mips@linux-mips.org
-L:     netdev@oss.sgi.com
+L:     netdev@vger.kernel.org
 S:     Supported
 
 MARVELL YUKON / SYSKONNECT DRIVER
@@ -1315,7 +1315,7 @@
 
 NETWORKING [GENERAL]
 P:     Networking Team
-M:     netdev@oss.sgi.com
+M:     netdev@vger.kernel.org
 L:     linux-net@vger.kernel.org
 S:     Maintained
 
@@ -1332,7 +1332,7 @@
 M:     yoshfuji@linux-ipv6.org
 P:     Patrick McHardy
 M:     kaber@coreworks.de
-L:     netdev@oss.sgi.com
+L:     netdev@vger.kernel.org
 S:     Maintained
 
 NFS CLIENT
@@ -1529,7 +1529,7 @@
 PRISM54 WIRELESS DRIVER
 P:     Prism54 Development Team
 M:     prism54-private@prism54.org
-L:     netdev@oss.sgi.com
+L:     netdev@vger.kernel.org
 W:     http://prism54.org
 S:     Maintained
 
diff -urN linux/Makefile linux/Makefile
--- linux/Makefile      2005/06/01 14:15:27     1.119.2.39
+++ linux/Makefile      2005/09/23 20:41:15     1.119.2.40
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
-SUBLEVEL = 31
-EXTRAVERSION =
+SUBLEVEL = 32
+EXTRAVERSION = -rc1
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -urN linux/Documentation/Configure.help linux/Documentation/Configure.help
--- linux/Documentation/Attic/Configure.help    2005/03/18 12:13:19     
1.109.2.56
+++ linux/Documentation/Attic/Configure.help    2005/09/23 20:41:15     
1.109.2.57
@@ -9978,9 +9978,7 @@
 CONFIG_PPPOE
   Support for PPP over Ethernet.
 
-  This driver requires the current pppd from the "ppp" CVS repository
-  on cvs.samba.org.  The required support will be present in the next
-  ppp release (2.4.2).
+  This driver requires a ppp release >= 2.4.2.
 
 Wireless LAN (non-hamradio)
 CONFIG_NET_RADIO
@@ -28990,6 +28988,9 @@
   the TEA algorithm to address a potential key weakness
   in the TEA algorithm.
 
+  Xtendend Encryption Tiny Algorithm is a mis-implementation
+  of the XTEA algorithm for compatibility purposes.
+
 CONFIG_CRYPTO_ARC4
   ARC4 cipher algorithm.
   
diff -urN linux/Documentation/cciss.txt linux/Documentation/cciss.txt
--- linux/Documentation/cciss.txt       2004/08/14 18:38:44     1.4.2.5
+++ linux/Documentation/cciss.txt       2005/09/23 20:41:16     1.4.2.6
@@ -15,7 +15,11 @@
        * SA 6400 U320 Expansion Module
        * SA 6i
        * SA 6422
-       * SA V100
+       * SA P600
+       * SA P400
+       * SA P400i
+       * SA E200
+       * SA E200i
 
 If nodes are not already created in the /dev/cciss directory
 
diff -urN linux/Documentation/crypto/api-intro.txt 
linux/Documentation/crypto/api-intro.txt
--- linux/Documentation/crypto/api-intro.txt    2004/11/19 00:28:31     1.7.2.6
+++ linux/Documentation/crypto/api-intro.txt    2005/09/23 20:41:17     1.7.2.7
@@ -221,6 +221,7 @@
 
 TEA/XTEA algorithm contributors:
   Aaron Grothe
+  Michael Ringe
 
 Khazad algorithm contributors:
   Aaron Grothe
diff -urN linux/Documentation/networking/vortex.txt 
linux/Documentation/networking/vortex.txt
--- linux/Documentation/networking/vortex.txt   2002/06/26 22:35:01     1.10.2.1
+++ linux/Documentation/networking/vortex.txt   2005/09/23 20:41:17     1.10.2.2
@@ -12,7 +12,7 @@
 Please report problems to one or more of:
 
   Andrew Morton <andrewm@uow.edu.au>
-  Netdev mailing list <netdev@oss.sgi.com>
+  Netdev mailing list <netdev@vger.kernel.org>
   Linux kernel mailing list <linux-kernel@vger.kernel.org>
 
 Please note the 'Reporting and Diagnosing Problems' section at the end
diff -urN linux/arch/alpha/kernel/Makefile linux/arch/alpha/kernel/Makefile
--- linux/arch/alpha/kernel/Makefile    2003/11/17 01:07:30     1.19.2.3
+++ linux/arch/alpha/kernel/Makefile    2005/09/23 20:41:18     1.19.2.4
@@ -76,7 +76,7 @@
 obj-y    += sys_alcor.o
 endif
 ifneq 
($(CONFIG_ALPHA_CABRIOLET)$(CONFIG_ALPHA_EB164)$(CONFIG_ALPHA_EB66P)$(CONFIG_ALPHA_LX164)$(CONFIG_ALPHA_PC164),)
-obj-y    += sys_cabriolet.o
+obj-y    += sys_cabriolet.o ns87312.o
 endif
 
 obj-$(CONFIG_ALPHA_DP264) += sys_dp264.o
diff -urN linux/arch/i386/kernel/apm.c linux/arch/i386/kernel/apm.c
--- linux/arch/i386/kernel/apm.c        2003/08/13 17:19:08     1.32.2.6
+++ linux/arch/i386/kernel/apm.c        2005/09/23 20:41:18     1.32.2.7
@@ -327,7 +327,7 @@
  * Save a segment register away
  */
 #define savesegment(seg, where) \
-               __asm__ __volatile__("movl %%" #seg ",%0" : "=m" (where))
+               __asm__ __volatile__("mov %%" #seg ",%0" : "=m" (where))
 
 /*
  * Maximum number of events stored
@@ -553,7 +553,7 @@
 
 #ifdef APM_ZERO_SEGS
 #      define APM_DECL_SEGS \
-               unsigned int saved_fs; unsigned int saved_gs;
+               unsigned short saved_fs; unsigned short saved_gs;
 #      define APM_DO_SAVE_SEGS \
                savesegment(fs, saved_fs); savesegment(gs, saved_gs)
 #      define APM_DO_ZERO_SEGS \
diff -urN linux/arch/i386/kernel/pci-irq.c linux/arch/i386/kernel/pci-irq.c
--- linux/arch/i386/kernel/Attic/pci-irq.c      2005/05/25 17:14:22     
1.18.2.14
+++ linux/arch/i386/kernel/Attic/pci-irq.c      2005/09/23 20:41:18     
1.18.2.15
@@ -664,6 +664,13 @@
 static __init int via_router_probe(struct irq_router *r, struct pci_dev 
*router, u16 device)
 {
        /* FIXME: We should move some of the quirk fixup stuff here */
+
+       if (router->device == PCI_DEVICE_ID_VIA_82C686 &&
+               device == PCI_DEVICE_ID_VIA_82C586_0) {
+               /* Asus k7m bios wrongly reports 82C686A as 586-compatible */
+               device = PCI_DEVICE_ID_VIA_82C686;
+       }
+
        switch(device)
        {
                case PCI_DEVICE_ID_VIA_82C586_0:
diff -urN linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c
--- linux/arch/i386/kernel/process.c    2004/11/19 00:28:31     1.41.2.8
+++ linux/arch/i386/kernel/process.c    2005/09/23 20:41:18     1.41.2.9
@@ -544,7 +544,7 @@
  * Save a segment.
  */
 #define savesegment(seg,value) \
-       asm volatile("movl %%" #seg ",%0":"=m" (*(int *)&(value)))
+       asm volatile("mov %%" #seg ",%0":"=m" (value))
 
 int copy_thread(int nr, unsigned long clone_flags, unsigned long esp,
        unsigned long unused,
@@ -661,8 +661,8 @@
         * Save away %fs and %gs. No need to save %es and %ds, as
         * those are always kernel segments while inside the kernel.
         */
-       asm volatile("movl %%fs,%0":"=m" (*(int *)&prev->fs));
-       asm volatile("movl %%gs,%0":"=m" (*(int *)&prev->gs));
+       asm volatile("mov %%fs,%0":"=m" (prev->fs));
+       asm volatile("mov %%gs,%0":"=m" (prev->gs));
 
        /*
         * Restore %fs and %gs.
diff -urN linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c
--- linux/arch/i386/kernel/traps.c      2002/09/11 12:44:26     1.41.2.3
+++ linux/arch/i386/kernel/traps.c      2005/09/23 20:41:18     1.41.2.4
@@ -631,15 +631,14 @@
         */
        cwd = get_fpu_cwd(task);
        swd = get_fpu_swd(task);
-       switch (((~cwd) & swd & 0x3f) | (swd & 0x240)) {
+       switch (swd & ~cwd & 0x3f) {
                case 0x000:
                default:
                        break;
                case 0x001: /* Invalid Op */
-               case 0x041: /* Stack Fault */
-               case 0x241: /* Stack Fault | Direction */
+                       /* swd & 0x240 == 0x040: Stack Fault */
+                       /* swd & 0x240 == 0x240: Stack Fault | Direction */
                        info.si_code = FPE_FLTINV;
-                       /* Should we clear the SF or let user space do it ???? 
*/
                        break;
                case 0x002: /* Denormalize */
                case 0x010: /* Underflow */
diff -urN linux/arch/ia64/ia32/sys_ia32.c linux/arch/ia64/ia32/sys_ia32.c
--- linux/arch/ia64/ia32/sys_ia32.c     2005/03/18 12:13:20     1.22.2.12
+++ linux/arch/ia64/ia32/sys_ia32.c     2005/09/23 20:41:18     1.22.2.13
@@ -94,7 +94,7 @@
 static DECLARE_MUTEX(ia32_mmap_sem);
 
 static int
-nargs (unsigned int arg, char **ap)
+nargs (unsigned int arg, char **ap, int max)
 {
        unsigned int addr;
        int n, err;
@@ -107,6 +107,8 @@
                err = get_user(addr, (unsigned int *)A(arg));
                if (err)
                        return err;
+               if (n > max)
+                       return -E2BIG;
                if (ap)
                        *ap++ = (char *) A(addr);
                arg += sizeof(unsigned int);
@@ -128,10 +130,11 @@
        int na, ne, len;
        long r;
 
-       na = nargs(argv, NULL);
+       /* Allocates upto 2x MAX_ARG_PAGES */
+       na = nargs(argv, NULL, (MAX_ARG_PAGES*PAGE_SIZE) / sizeof(char *) - 1);
        if (na < 0)
                return na;
-       ne = nargs(envp, NULL);
+       ne = nargs(envp, NULL, (MAX_ARG_PAGES*PAGE_SIZE) / sizeof(char *) - 1 );
        if (ne < 0)
                return ne;
        len = (na + ne + 2) * sizeof(*av);
@@ -143,10 +146,10 @@
        av[na] = NULL;
        ae[ne] = NULL;
 
-       r = nargs(argv, av);
+       r = nargs(argv, av, na);
        if (r < 0)
                goto out;
-       r = nargs(envp, ae);
+       r = nargs(envp, ae, ne);
        if (r < 0)
                goto out;
 
diff -urN linux/arch/ia64/mm/fault.c linux/arch/ia64/mm/fault.c
--- linux/arch/ia64/mm/fault.c  2003/08/13 17:19:09     1.7.2.5
+++ linux/arch/ia64/mm/fault.c  2005/09/23 20:41:18     1.7.2.6
@@ -206,9 +206,6 @@
                return;
        }
 
-       if (done_with_exception(regs))
-               return;
-
        /*
         * Since we have no vma's for region 5, we might get here even if the 
address is
         * valid, due to the VHPT walker inserting a non present translation 
that becomes
@@ -219,6 +216,9 @@
        if (REGION_NUMBER(address) == 5 && 
mapped_kernel_page_is_present(address))
                return;
 
+       if (done_with_exception(regs))
+               return;
+
        /*
         * Oops. The kernel tried to access some bad page. We'll have to 
terminate things
         * with extreme prejudice.
diff -urN linux/arch/mips/.gdbinit linux/arch/mips/.gdbinit
--- linux/arch/mips/Attic/.gdbinit      2005-09-23 21:41:19.104779000 +0100     
1.1.1.1
+++ linux/arch/mips/Attic/.gdbinit      1970/01/01 00:00:00+0100
@@ -1,7 +0,0 @@
-echo Setting up the environment for debugging vmlinux...\n
-echo set remotedebug 0 \n
-set remotedebug 0
-echo cd arch/mips/kernel \n
-cd arch/mips/kernel
-echo target remote /dev/ttyS0 \n
-target remote /dev/ttyS0
diff -urN linux/arch/ppc/boot/lib/zlib.c linux/arch/ppc/boot/lib/zlib.c
--- linux/arch/ppc/boot/lib/Attic/zlib.c        2003/08/13 17:19:11     1.1.2.3
+++ linux/arch/ppc/boot/lib/Attic/zlib.c        2005/09/23 20:41:19     1.1.2.4
@@ -1278,7 +1278,7 @@
   {
     *t = (inflate_huft *)Z_NULL;
     *m = 0;
-    return Z_OK;
+    return Z_DATA_ERROR;
   }
 
 
@@ -1322,6 +1322,7 @@
     if ((j = *p++) != 0)
       v[x[j]++] = i;
   } while (++i < n);
+  n = x[g];                    /* set n to length of v */
 
 
   /* Generate the Huffman codes and for each, make the table entries */
diff -urN linux/arch/ppc/kernel/time.c linux/arch/ppc/kernel/time.c
--- linux/arch/ppc/kernel/time.c        2005/05/23 12:12:30     1.26.2.7
+++ linux/arch/ppc/kernel/time.c        2005/09/23 20:41:19     1.26.2.8
@@ -84,7 +84,7 @@
 
 extern unsigned long wall_jiffies;
 
-static long time_offset;
+static long timezone_offset;
 
 spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
 
@@ -187,7 +187,7 @@
                     xtime.tv_sec - last_rtc_update >= 659 &&
                     abs(xtime.tv_usec - (1000000-1000000/HZ)) < 500000/HZ &&
                     jiffies - wall_jiffies == 1) {
-                       if (ppc_md.set_rtc_time(xtime.tv_sec+1 + time_offset) 
== 0)
+                       if (ppc_md.set_rtc_time(xtime.tv_sec+1 + 
timezone_offset) == 0)
                                last_rtc_update = xtime.tv_sec+1;
                        else
                                /* Try again one minute later */
@@ -297,7 +297,7 @@
        unsigned old_stamp, stamp, elapsed;
 
         if (ppc_md.time_init != NULL)
-                time_offset = ppc_md.time_init();
+                timezone_offset = ppc_md.time_init();
 
        if (__USE_RTC()) {
                /* 601 processor: dec counts down by 128 every 128ns */
@@ -344,9 +344,9 @@
        /* If platform provided a timezone (pmac), we correct the time
         * using do_sys_settimeofday() which in turn calls warp_clock()
         */
-        if (time_offset) {
+        if (timezone_offset) {
                struct timezone tz;
-               tz.tz_minuteswest = -time_offset / 60;
+               tz.tz_minuteswest = -timezone_offset / 60;
                tz.tz_dsttime = 0;
                do_sys_settimeofday(NULL, &tz);
         }
diff -urN linux/arch/ppc64/boot/zlib.c linux/arch/ppc64/boot/zlib.c
--- linux/arch/ppc64/boot/zlib.c        2003/08/13 17:19:12     1.1.2.2
+++ linux/arch/ppc64/boot/zlib.c        2005/09/23 20:41:19     1.1.2.3
@@ -1338,6 +1338,7 @@
     if ((j = *p++) != 0)
       v[x[j]++] = i;
   } while (++i < n);
+  n = x[g];                    /* set n to length of v */
 
 
   /* Generate the Huffman codes and for each, make the table entries */
diff -urN linux/arch/ppc64/kernel/ioctl32.c linux/arch/ppc64/kernel/ioctl32.c
--- linux/arch/ppc64/kernel/ioctl32.c   2005/01/09 19:34:01     1.1.2.7
+++ linux/arch/ppc64/kernel/ioctl32.c   2005/09/23 20:41:19     1.1.2.8
@@ -876,13 +876,15 @@
                r = (void *) &r4;
        }
 
-       if (ret)
-               return -EFAULT;
+       if (ret) {
+               ret = -EFAULT;
+               goto out;
+       }
 
        set_fs (KERNEL_DS);
        ret = sys_ioctl (fd, cmd, (long) r);
        set_fs (old_fs);
-
+out:
        if (mysock)
                sockfd_put(mysock);
 
diff -urN linux/arch/sparc64/kernel/ioctl32.c 
linux/arch/sparc64/kernel/ioctl32.c
--- linux/arch/sparc64/kernel/ioctl32.c 2005/03/18 12:13:24     1.47.2.16
+++ linux/arch/sparc64/kernel/ioctl32.c 2005/09/23 20:41:19     1.47.2.17
@@ -809,13 +809,15 @@
                r = (void *) &r4;
        }
 
-       if (ret)
-               return -EFAULT;
+       if (ret) {
+               ret = -EFAULT;
+               goto out;
+       }
 
        set_fs (KERNEL_DS);
        ret = sys_ioctl (fd, cmd, (long) r);
        set_fs (old_fs);
-
+out:
        if (mysock)
                sockfd_put(mysock);
 
diff -urN linux/arch/sparc64/kernel/sparc64_ksyms.c 
linux/arch/sparc64/kernel/sparc64_ksyms.c
--- linux/arch/sparc64/kernel/sparc64_ksyms.c   2005/03/18 12:13:24     1.41.2.8
+++ linux/arch/sparc64/kernel/sparc64_ksyms.c   2005/09/23 20:41:20     1.41.2.9
@@ -63,7 +63,6 @@
 extern void die_if_kernel(char *str, struct pt_regs *regs);
 void _sigpause_common (unsigned int set, struct pt_regs *);
 extern void *__bzero(void *, size_t);
-extern void *__bzero_noasi(void *, size_t);
 extern void *__memscan_zero(void *, size_t);
 extern void *__memscan_generic(void *, int, size_t);
 extern int __memcmp(const void *, const void *, __kernel_size_t);
diff -urN linux/arch/sparc64/kernel/sys_sparc32.c 
linux/arch/sparc64/kernel/sys_sparc32.c
--- linux/arch/sparc64/kernel/sys_sparc32.c     2005/04/05 19:09:55     
1.60.2.16
+++ linux/arch/sparc64/kernel/sys_sparc32.c     2005/09/23 20:41:20     
1.60.2.17
@@ -50,6 +50,7 @@
 #include <linux/in.h>
 #include <linux/icmpv6.h>
 #include <linux/sysctl.h>
+#include <linux/vmalloc.h>
 #include <linux/dnotify.h>
 #include <linux/netfilter_ipv4/ip_tables.h>
 
@@ -2919,12 +2920,12 @@
        if (optlen != kreplsize)
                return -ENOPROTOOPT;
 
-       krepl = (struct ipt_replace *)kmalloc(kreplsize, GFP_KERNEL);
+       krepl = (struct ipt_replace *)vmalloc(kreplsize);
        if (krepl == NULL)
                return -ENOMEM;
 
        if (copy_from_user(krepl, optval, kreplsize)) {
-               kfree(krepl);
+               vfree(krepl);
                return -EFAULT;
        }
 
@@ -2932,10 +2933,9 @@
                ((struct ipt_replace32 *)krepl)->counters);
 
        kcountersize = krepl->num_counters * sizeof(struct ipt_counters);
-       krepl->counters = (struct ipt_counters *)kmalloc(
-                                       kcountersize, GFP_KERNEL);
+       krepl->counters = (struct ipt_counters *)vmalloc(kcountersize);
        if (krepl->counters == NULL) {
-               kfree(krepl);
+               vfree(krepl);
                return -ENOMEM;
        }
 
@@ -2949,8 +2949,8 @@
                copy_to_user(counters32, krepl->counters, kcountersize))
                        ret = -EFAULT;
 
-       kfree(krepl->counters);
-       kfree(krepl);
+       vfree(krepl->counters);
+       vfree(krepl);
 
        return ret;
 }
@@ -4205,7 +4205,7 @@
 
                old_fs = get_fs();
                set_fs(KERNEL_DS);
-               ret = sys_utimes(kfilename, &ktvs[0]);
+               ret = sys_utimes(kfilename, (tvs ? &ktvs[0] : NULL));
                set_fs(old_fs);
 
                putname(kfilename);
diff -urN linux/arch/sparc64/solaris/socket.c 
linux/arch/sparc64/solaris/socket.c
--- linux/arch/sparc64/solaris/socket.c 2001/03/09 20:33:53     1.6
+++ linux/arch/sparc64/solaris/socket.c 2005/09/23 20:41:20     1.6.2.1
@@ -410,8 +410,10 @@
                unsigned long *kcmsg;
                __kernel_size_t32 cmlen;
 
-               if(kern_msg.msg_controllen > sizeof(ctl) &&
-                  kern_msg.msg_controllen <= 256) {
+               if (kern_msg.msg_controllen <= sizeof(__kernel_size_t32))
+                       return -EINVAL;
+
+               if(kern_msg.msg_controllen > sizeof(ctl)) {
                        err = -ENOBUFS;
                        ctl_buf = kmalloc(kern_msg.msg_controllen, GFP_KERNEL);
                        if(!ctl_buf)
diff -urN linux/arch/x86_64/ia32/ia32_ioctl.c 
linux/arch/x86_64/ia32/ia32_ioctl.c
--- linux/arch/x86_64/ia32/ia32_ioctl.c 2005/01/09 19:34:02     1.6.2.10
+++ linux/arch/x86_64/ia32/ia32_ioctl.c 2005/09/23 20:41:20     1.6.2.11
@@ -816,6 +816,11 @@
 
 extern struct socket *sockfd_lookup(int fd, int *err);
 
+extern __inline__ void sockfd_put(struct socket *sock)
+{
+       fput(sock->file);
+}
+
 static int routing_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
        int ret;
@@ -857,12 +862,17 @@
                r = (void *) &r4;
        }
 
-       if (ret)
-               return -EFAULT;
+       if (ret) {
+               ret = -EFAULT;
+               goto out;
+       }
 
        set_fs (KERNEL_DS);
        ret = sys_ioctl (fd, cmd, (long) r);
        set_fs (old_fs);
+out:
+       if (mysock)
+               sockfd_put(mysock);
 
        return ret;
 }
@@ -2766,17 +2776,24 @@
 static int tiocgdev(unsigned fd, unsigned cmd,  unsigned int *ptr) 
 { 
 
-       struct file *file = fget(fd);
+       struct file *file;
        struct tty_struct *real_tty;
+       int ret;
 
+       file = fget(fd);
        if (!file)
                return -EBADF;
+       ret = -EINVAL;
        if (file->f_op->ioctl != tty_ioctl)
-               return -EINVAL; 
+               goto out;
        real_tty = (struct tty_struct *)file->private_data;
        if (!real_tty)  
-               return -EINVAL; 
-       return put_user(kdev_t_to_nr(real_tty->device), ptr); 
+               goto out;
+       ret = put_user(kdev_t_to_nr(real_tty->device), ptr); 
+out:
+       fput(file);
+
+       return ret;
 } 
 
 
diff -urN linux/arch/x86_64/ia32/sys_ia32.c linux/arch/x86_64/ia32/sys_ia32.c
--- linux/arch/x86_64/ia32/sys_ia32.c   2004/11/29 17:47:16     1.3.2.12
+++ linux/arch/x86_64/ia32/sys_ia32.c   2005/09/23 20:41:20     1.3.2.13
@@ -2200,7 +2200,7 @@
        return ret;
 } 
 
-static int nargs(u32 src, char **dst) 
+static int nargs(u32 src, char **dst, int max) 
 { 
        int cnt;
        u32 val; 
@@ -2210,13 +2210,13 @@
                int ret = get_user(val, (__u32 *)(u64)src); 
                if (ret)
                        return ret;
+               if (cnt > max)
+                       return -E2BIG; 
                if (dst)
                        dst[cnt] = (char *)(u64)val; 
                cnt++;
                src += 4;
-               if (cnt >= (MAX_ARG_PAGES * PAGE_SIZE) / sizeof(char *))
-                       return -E2BIG; 
-       } while(val); 
+               } while(val); 
        if (dst)
                dst[cnt-1] = 0; 
        return cnt; 
@@ -2230,13 +2230,14 @@
        int ret;
        unsigned sz = 0; 
        
+       /* Can actually allocate 2*MAX_ARG_PAGES */
        if (argv) {
-       na = nargs(argv, NULL); 
+       na = nargs(argv, NULL, (MAX_ARG_PAGES * PAGE_SIZE)/sizeof(char*) - 1); 
        if (na < 0) 
                return -EFAULT; 
        }       
        if (envp) { 
-       ne = nargs(envp, NULL); 
+       ne = nargs(envp, NULL, (MAX_ARG_PAGES * PAGE_SIZE)/sizeof(char*) - 1); 
        if (ne < 0) 
                return -EFAULT; 
        }
@@ -2252,13 +2253,13 @@
        } 
        
        if (argv) { 
-       ret = nargs(argv, buf);
+       ret = nargs(argv, buf, na);
        if (ret < 0)
                goto free;
        }
 
        if (envp) { 
-       ret = nargs(envp, buf + na); 
+       ret = nargs(envp, buf + na, ne); 
        if (ret < 0)
                goto free; 
        }
diff -urN linux/arch/x86_64/kernel/io_apic.c linux/arch/x86_64/kernel/io_apic.c
--- linux/arch/x86_64/kernel/io_apic.c  2005/03/18 12:13:24     1.2.2.9
+++ linux/arch/x86_64/kernel/io_apic.c  2005/09/23 20:41:21     1.2.2.10
@@ -222,7 +222,6 @@
 
 __setup("apic", ioapic_setup);
 
-#ifndef CONFIG_SMP
 #include <asm/pci-direct.h>
 #include <linux/pci_ids.h>
 #include <linux/pci.h>
@@ -279,7 +278,6 @@
                }
        }
 } 
-#endif
 
 static int __init ioapic_pirq_setup(char *str)
 {
diff -urN linux/arch/x86_64/kernel/pci-gart.c 
linux/arch/x86_64/kernel/pci-gart.c
--- linux/arch/x86_64/kernel/pci-gart.c 2005/05/25 17:14:23     1.1.2.11
+++ linux/arch/x86_64/kernel/pci-gart.c 2005/09/23 20:41:21     1.1.2.12
@@ -47,6 +47,10 @@
 extern int fallback_aper_order;
 extern int fallback_aper_force;
 
+#ifdef CONFIG_SWIOTLB
+extern char *io_tlb_start, *io_tlb_end;
+#endif
+ 
 /* Allocation bitmap for the remapping area */ 
 static spinlock_t iommu_bitmap_lock = SPIN_LOCK_UNLOCKED;
 static unsigned long *iommu_gart_bitmap; /* guarded by iommu_bitmap_lock */
@@ -234,10 +238,10 @@
                         void *vaddr, dma_addr_t bus)
 {
        unsigned long iommu_page;
-       extern  char *io_tlb_start, *io_tlb_end;
- 
+
        size = round_up(size, PAGE_SIZE); 
 #ifdef CONFIG_SWIOTLB
+       /* Overlap should not happen */
        if (swiotlb && vaddr >= (void *)io_tlb_start &&
            vaddr < (void *)io_tlb_end) {
                swiotlb_unmap_single (hwdev, bus, size, PCI_DMA_TODEVICE);
diff -urN linux/arch/x86_64/kernel/process.c linux/arch/x86_64/kernel/process.c
--- linux/arch/x86_64/kernel/process.c  2005/05/05 13:43:41     1.4.2.10
+++ linux/arch/x86_64/kernel/process.c  2005/09/23 20:41:21     1.4.2.11
@@ -526,10 +526,10 @@
        p->thread.fs = me->thread.fs;
        p->thread.gs = me->thread.gs;
 
-       asm("movl %%gs,%0" : "=m" (p->thread.gsindex));
-       asm("movl %%fs,%0" : "=m" (p->thread.fsindex));
-       asm("movl %%es,%0" : "=m" (p->thread.es));
-       asm("movl %%ds,%0" : "=m" (p->thread.ds));
+       asm("mov %%gs,%0" : "=m" (p->thread.gsindex));
+       asm("mov %%fs,%0" : "=m" (p->thread.fsindex));
+       asm("mov %%es,%0" : "=m" (p->thread.es));
+       asm("mov %%ds,%0" : "=m" (p->thread.ds));
 
        unlazy_fpu(current);    
        p->thread.i387 = current->thread.i387;
@@ -574,11 +574,11 @@
        /* 
         * Switch DS and ES.     
         */
-       asm volatile("movl %%es,%0" : "=m" (prev->es)); 
+       asm volatile("mov %%es,%0" : "=m" (prev->es)); 
        if (unlikely(next->es | prev->es))
                loadsegment(es, next->es); 
        
-       asm volatile ("movl %%ds,%0" : "=m" (prev->ds)); 
+       asm volatile ("mov %%ds,%0" : "=m" (prev->ds)); 
        if (unlikely(next->ds | prev->ds))
                loadsegment(ds, next->ds);
 
@@ -587,7 +587,7 @@
         */
        { 
                unsigned fsindex;
-               asm volatile("movl %%fs,%0" : "=g" (fsindex)); 
+               asm volatile("movl %%fs,%0" : "=r" (fsindex)); 
                /* segment register != 0 always requires a reload. 
                   also reload when it has changed. 
                   when prev process used 64bit base always reload
@@ -608,7 +608,7 @@
        }
        {
                unsigned gsindex;
-               asm volatile("movl %%gs,%0" : "=g" (gsindex)); 
+               asm volatile("movl %%gs,%0" : "=r" (gsindex)); 
                if (unlikely((gsindex | next->gsindex) || prev->gs)) {
                        load_gs_index(next->gsindex);
                        if (gsindex)
diff -urN linux/arch/x86_64/kernel/ptrace.c linux/arch/x86_64/kernel/ptrace.c
--- linux/arch/x86_64/kernel/ptrace.c   2003/07/05 03:23:35     1.3.2.3
+++ linux/arch/x86_64/kernel/ptrace.c   2005/09/23 20:41:21     1.3.2.4
@@ -114,13 +114,13 @@
                        child->thread.es = value & 0xffff;
                        return 0;
                case offsetof(struct user_regs_struct,fs_base):
-                       if (!((value >> 48) == 0 || (value >> 48) == 0xffff))
-                               return -EIO; 
+                       if (value >= TASK_SIZE)
+                               return -EIO;
                        child->thread.fs = value;
                        return 0;
                case offsetof(struct user_regs_struct,gs_base):
-                       if (!((value >> 48) == 0 || (value >> 48) == 0xffff))
-                               return -EIO; 
+                       if (value >= TASK_SIZE)
+                               return -EIO;
                        child->thread.gs = value;
                        return 0;
                case offsetof(struct user_regs_struct, eflags):
@@ -139,6 +139,11 @@
                                return -EIO;
                        value &= 0xffff;
             break;
+               case offsetof(struct user_regs_struct, rip):
+                       /* Check if the new RIP address is canonical */
+                       if (value >= TASK_SIZE)
+                               return -EIO;
+                       break;
        }      
        put_stack_long(child, regno - sizeof(struct pt_regs), value);
        return 0;
diff -urN linux/arch/x86_64/kernel/setup.c linux/arch/x86_64/kernel/setup.c
--- linux/arch/x86_64/kernel/setup.c    2005/03/18 12:13:24     1.2.2.11
+++ linux/arch/x86_64/kernel/setup.c    2005/09/23 20:41:21     1.2.2.12
@@ -304,7 +304,7 @@
 #endif
 
        paging_init();
-#if !defined(CONFIG_SMP) && defined(CONFIG_X86_IO_APIC)
+#if defined(CONFIG_X86_IO_APIC)
        extern void check_ioapic(void);
        check_ioapic();
 #endif
diff -urN linux/arch/x86_64/kernel/traps.c linux/arch/x86_64/kernel/traps.c
--- linux/arch/x86_64/kernel/traps.c    2004/04/16 03:14:13     1.3.2.8
+++ linux/arch/x86_64/kernel/traps.c    2005/09/23 20:41:21     1.3.2.9
@@ -857,7 +857,7 @@
        set_intr_gate(9,&coprocessor_segment_overrun);
        set_intr_gate(10,&invalid_TSS);
        set_intr_gate(11,&segment_not_present);
-       set_intr_gate_ist(12,&stack_segment,STACKFAULT_STACK);
+       set_intr_gate(12,&stack_segment);
        set_intr_gate(13,&general_protection);
        set_intr_gate(14,&page_fault);
        set_intr_gate(15,&spurious_interrupt_bug);
diff -urN linux/crypto/tcrypt.c linux/crypto/tcrypt.c
--- linux/crypto/tcrypt.c       2004/11/19 00:28:36     1.8.2.6
+++ linux/crypto/tcrypt.c       2005/09/23 20:41:21     1.8.2.7
@@ -64,7 +64,7 @@
        "des", "md5", "des3_ede", "rot13", "sha1", "sha256", "blowfish",
        "twofish", "serpent", "sha384", "sha512", "md4", "aes", "cast6", 
        "arc4", "michael_mic", "deflate", "tea", "xtea", "khazad", 
-       "wp512", "wp384", "wp256", "tnepres", "anubis", NULL
+       "wp512", "wp384", "wp256", "tnepres", "anubis", "xeta", NULL
 };
 
 static void
@@ -590,6 +590,10 @@
                test_cipher ("anubis", MODE_CBC, ENCRYPT, 
anubis_cbc_enc_tv_template, ANUBIS_CBC_ENC_TEST_VECTORS);
                test_cipher ("anubis", MODE_CBC, DECRYPT, 
anubis_cbc_dec_tv_template, ANUBIS_CBC_ENC_TEST_VECTORS);
 
+               //XETA
+               test_cipher ("xeta", MODE_ECB, ENCRYPT, xeta_enc_tv_template, 
XETA_ENC_TEST_VECTORS);
+               test_cipher ("xeta", MODE_ECB, DECRYPT, xeta_dec_tv_template, 
XETA_DEC_TEST_VECTORS);
+
                test_hash("sha384", sha384_tv_template, SHA384_TEST_VECTORS);
                test_hash("sha512", sha512_tv_template, SHA512_TEST_VECTORS);
                test_hash("wp512", wp512_tv_template, WP512_TEST_VECTORS);
@@ -725,6 +729,11 @@
                test_cipher ("anubis", MODE_CBC, DECRYPT, 
anubis_cbc_dec_tv_template, ANUBIS_CBC_ENC_TEST_VECTORS);
                break;
 
+       case 30:
+               test_cipher ("xeta", MODE_ECB, ENCRYPT, xeta_enc_tv_template, 
XETA_ENC_TEST_VECTORS);
+               test_cipher ("xeta", MODE_ECB, DECRYPT, xeta_dec_tv_template, 
XETA_DEC_TEST_VECTORS);
+               break;
+
 #ifdef CONFIG_CRYPTO_HMAC
        case 100:
                test_hmac("md5", hmac_md5_tv_template, HMAC_MD5_TEST_VECTORS);
diff -urN linux/crypto/tcrypt.h linux/crypto/tcrypt.h
--- linux/crypto/tcrypt.h       2004/11/19 00:28:36     1.6.2.6
+++ linux/crypto/tcrypt.h       2005/09/23 20:41:21     1.6.2.7
@@ -2085,7 +2085,7 @@
                .klen   = 16,
                .input  = { [0 ... 8] = 0x00 },
                .ilen   = 8,
-               .result = { 0xaa, 0x22, 0x96, 0xe5, 0x6c, 0x61, 0xf3, 0x45 },
+               .result = { 0xd8, 0xd4, 0xe9, 0xde, 0xd9, 0x1e, 0x13, 0xf7 },
                .rlen   = 8,
        }, {
                .key    = { 0x2b, 0x02, 0x05, 0x68, 0x06, 0x14, 0x49, 0x76,
@@ -2093,13 +2093,13 @@
                .klen   = 16,
                .input  = { 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x65, 0x2e },
                .ilen   = 8,
-               .result = { 0x82, 0x3e, 0xeb, 0x35, 0xdc, 0xdd, 0xd9, 0xc3 },
+               .result = { 0x94, 0xeb, 0xc8, 0x96, 0x84, 0x6a, 0x49, 0xa8 },
                .rlen   = 8,
        }, {
                .key    = { 0x09, 0x65, 0x43, 0x11, 0x66, 0x44, 0x39, 0x25,
                            0x51, 0x3a, 0x16, 0x10, 0x0a, 0x08, 0x12, 0x6e },
                .klen   = 16,
-               .input  = { 0x6c, 0x6f, 0x6e, 0x67, 0x65, 0x72, 0x5f, 0x74, 
+               .input  = { 0x3e, 0xce, 0xae, 0x22, 0x60, 0x56, 0xa8, 0x9d,
                            0x65, 0x73, 0x74, 0x5f, 0x76, 0x65, 0x63, 0x74 },
                .ilen   = 16,
                .result = { 0xe2, 0x04, 0xdb, 0xf2, 0x89, 0x85, 0x9e, 0xea, 
@@ -2114,10 +2114,10 @@
                            0x79, 0x6f, 0x75, 0x21, 0x21, 0x21, 0x20, 0x72, 
                            0x65, 0x61, 0x6c, 0x6c, 0x79, 0x21, 0x21, 0x21 },
                .ilen   = 32,
-               .result = { 0x0b, 0x03, 0xcd, 0x8a, 0xbe, 0x95, 0xfd, 0xb1, 
-                           0xc1, 0x44, 0x91, 0x0b, 0xa5, 0xc9, 0x1b, 0xb4, 
-                           0xa9, 0xda, 0x1e, 0x9e, 0xb1, 0x3e, 0x2a, 0x8f, 
-                           0xea, 0xa5, 0x6a, 0x85, 0xd1, 0xf4, 0xa8, 0xa5 },
+               .result = { 0x99, 0x81, 0x9f, 0x5d, 0x6f, 0x4b, 0x31, 0x3a,
+                           0x86, 0xff, 0x6f, 0xd0, 0xe3, 0x87, 0x70, 0x07,
+                           0x4d, 0xb8, 0xcf, 0xf3, 0x99, 0x50, 0xb3, 0xd4,
+                           0x73, 0xa2, 0xfa, 0xc9, 0x16, 0x59, 0x5d, 0x81 },
                .rlen   = 32,
        }
 };
@@ -2127,7 +2127,7 @@
        {
                .key    = { [0 ... 15] = 0x00 },
                .klen   = 16,
-               .input  = { 0xaa, 0x22, 0x96, 0xe5, 0x6c, 0x61, 0xf3, 0x45 },
+               .input  = { 0xd8, 0xd4, 0xe9, 0xde, 0xd9, 0x1e, 0x13, 0xf7 },
                .ilen   = 8,
                .result = { [0 ... 8] = 0x00 },
                .rlen   = 8,
@@ -2135,7 +2135,7 @@
                .key    = { 0x2b, 0x02, 0x05, 0x68, 0x06, 0x14, 0x49, 0x76,
                            0x77, 0x5d, 0x0e, 0x26, 0x6c, 0x28, 0x78, 0x43 },
                .klen   = 16,
-               .input  = { 0x82, 0x3e, 0xeb, 0x35, 0xdc, 0xdd, 0xd9, 0xc3 },
+               .input  = { 0x94, 0xeb, 0xc8, 0x96, 0x84, 0x6a, 0x49, 0xa8 },
                .ilen   = 8,
                .result = { 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x65, 0x2e },
                .rlen   = 8,
@@ -2143,8 +2143,8 @@
                .key    = { 0x09, 0x65, 0x43, 0x11, 0x66, 0x44, 0x39, 0x25,
                            0x51, 0x3a, 0x16, 0x10, 0x0a, 0x08, 0x12, 0x6e },
                .klen   = 16,
-               .input  = { 0xe2, 0x04, 0xdb, 0xf2, 0x89, 0x85, 0x9e, 0xea, 
-                           0x61, 0x35, 0xaa, 0xed, 0xb5, 0xcb, 0x71, 0x2c },
+               .input  = { 0x3e, 0xce, 0xae, 0x22, 0x60, 0x56, 0xa8, 0x9d,
+                           0x77, 0x4d, 0xd4, 0xb4, 0x87, 0x24, 0xe3, 0x9a },
                .ilen   = 16,
                .result = { 0x6c, 0x6f, 0x6e, 0x67, 0x65, 0x72, 0x5f, 0x74, 
                            0x65, 0x73, 0x74, 0x5f, 0x76, 0x65, 0x63, 0x74 },
@@ -2153,10 +2153,10 @@
                .key    = { 0x4d, 0x76, 0x32, 0x17, 0x05, 0x3f, 0x75, 0x2c,
                            0x5d, 0x04, 0x16, 0x36, 0x15, 0x72, 0x63, 0x2f },
                .klen   = 16,
-               .input  = { 0x0b, 0x03, 0xcd, 0x8a, 0xbe, 0x95, 0xfd, 0xb1, 
-                           0xc1, 0x44, 0x91, 0x0b, 0xa5, 0xc9, 0x1b, 0xb4, 
-                           0xa9, 0xda, 0x1e, 0x9e, 0xb1, 0x3e, 0x2a, 0x8f, 
-                           0xea, 0xa5, 0x6a, 0x85, 0xd1, 0xf4, 0xa8, 0xa5 },
+               .input  = { 0x99, 0x81, 0x9f, 0x5d, 0x6f, 0x4b, 0x31, 0x3a,
+                           0x86, 0xff, 0x6f, 0xd0, 0xe3, 0x87, 0x70, 0x07,
+                           0x4d, 0xb8, 0xcf, 0xf3, 0x99, 0x50, 0xb3, 0xd4,
+                           0x73, 0xa2, 0xfa, 0xc9, 0x16, 0x59, 0x5d, 0x81 },
                .ilen   = 32,
                .result = { 0x54, 0x65, 0x61, 0x20, 0x69, 0x73, 0x20, 0x67, 
                            0x6f, 0x6f, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 
@@ -2469,6 +2469,100 @@
        },
 };
 
+/* 
+ * XETA test vectors 
+ */
+#define XETA_ENC_TEST_VECTORS  4
+#define XETA_DEC_TEST_VECTORS  4
+
+struct cipher_testvec xeta_enc_tv_template[] =
+{
+       {
+               .key    = { [0 ... 15] = 0x00 },
+               .klen   = 16,
+               .input  = { [0 ... 8] = 0x00 },
+               .ilen   = 8,
+               .result = { 0xaa, 0x22, 0x96, 0xe5, 0x6c, 0x61, 0xf3, 0x45 },
+               .rlen   = 8,
+       }, {
+               .key    = { 0x2b, 0x02, 0x05, 0x68, 0x06, 0x14, 0x49, 0x76,
+                           0x77, 0x5d, 0x0e, 0x26, 0x6c, 0x28, 0x78, 0x43 },
+               .klen   = 16,
+               .input  = { 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x65, 0x2e },
+               .ilen   = 8,
+               .result = { 0x82, 0x3e, 0xeb, 0x35, 0xdc, 0xdd, 0xd9, 0xc3 },
+               .rlen   = 8,
+       }, {
+               .key    = { 0x09, 0x65, 0x43, 0x11, 0x66, 0x44, 0x39, 0x25,
+                           0x51, 0x3a, 0x16, 0x10, 0x0a, 0x08, 0x12, 0x6e },
+               .klen   = 16,
+               .input  = { 0x6c, 0x6f, 0x6e, 0x67, 0x65, 0x72, 0x5f, 0x74, 
+                           0x65, 0x73, 0x74, 0x5f, 0x76, 0x65, 0x63, 0x74 },
+               .ilen   = 16,
+               .result = { 0xe2, 0x04, 0xdb, 0xf2, 0x89, 0x85, 0x9e, 0xea, 
+                           0x61, 0x35, 0xaa, 0xed, 0xb5, 0xcb, 0x71, 0x2c },
+               .rlen   = 16,
+       }, {
+               .key    = { 0x4d, 0x76, 0x32, 0x17, 0x05, 0x3f, 0x75, 0x2c,
+                           0x5d, 0x04, 0x16, 0x36, 0x15, 0x72, 0x63, 0x2f },
+               .klen   = 16,
+               .input  = { 0x54, 0x65, 0x61, 0x20, 0x69, 0x73, 0x20, 0x67, 
+                           0x6f, 0x6f, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 
+                           0x79, 0x6f, 0x75, 0x21, 0x21, 0x21, 0x20, 0x72, 
+                           0x65, 0x61, 0x6c, 0x6c, 0x79, 0x21, 0x21, 0x21 },
+               .ilen   = 32,
+               .result = { 0x0b, 0x03, 0xcd, 0x8a, 0xbe, 0x95, 0xfd, 0xb1, 
+                           0xc1, 0x44, 0x91, 0x0b, 0xa5, 0xc9, 0x1b, 0xb4, 
+                           0xa9, 0xda, 0x1e, 0x9e, 0xb1, 0x3e, 0x2a, 0x8f, 
+                           0xea, 0xa5, 0x6a, 0x85, 0xd1, 0xf4, 0xa8, 0xa5 },
+               .rlen   = 32,
+       }
+};
+
+struct cipher_testvec xeta_dec_tv_template[] =
+{
+       {
+               .key    = { [0 ... 15] = 0x00 },
+               .klen   = 16,
+               .input  = { 0xaa, 0x22, 0x96, 0xe5, 0x6c, 0x61, 0xf3, 0x45 },
+               .ilen   = 8,
+               .result = { [0 ... 8] = 0x00 },
+               .rlen   = 8,
+       }, {
+               .key    = { 0x2b, 0x02, 0x05, 0x68, 0x06, 0x14, 0x49, 0x76,
+                           0x77, 0x5d, 0x0e, 0x26, 0x6c, 0x28, 0x78, 0x43 },
+               .klen   = 16,
+               .input  = { 0x82, 0x3e, 0xeb, 0x35, 0xdc, 0xdd, 0xd9, 0xc3 },
+               .ilen   = 8,
+               .result = { 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x65, 0x2e },
+               .rlen   = 8,
+       }, {
+               .key    = { 0x09, 0x65, 0x43, 0x11, 0x66, 0x44, 0x39, 0x25,
+                           0x51, 0x3a, 0x16, 0x10, 0x0a, 0x08, 0x12, 0x6e },
+               .klen   = 16,
+               .input  = { 0xe2, 0x04, 0xdb, 0xf2, 0x89, 0x85, 0x9e, 0xea, 
+                           0x61, 0x35, 0xaa, 0xed, 0xb5, 0xcb, 0x71, 0x2c },
+               .ilen   = 16,
+               .result = { 0x6c, 0x6f, 0x6e, 0x67, 0x65, 0x72, 0x5f, 0x74, 
+                           0x65, 0x73, 0x74, 0x5f, 0x76, 0x65, 0x63, 0x74 },
+               .rlen   = 16,
+       }, {
+               .key    = { 0x4d, 0x76, 0x32, 0x17, 0x05, 0x3f, 0x75, 0x2c,
+                           0x5d, 0x04, 0x16, 0x36, 0x15, 0x72, 0x63, 0x2f },
+               .klen   = 16,
+               .input  = { 0x0b, 0x03, 0xcd, 0x8a, 0xbe, 0x95, 0xfd, 0xb1, 
+                           0xc1, 0x44, 0x91, 0x0b, 0xa5, 0xc9, 0x1b, 0xb4, 
+                           0xa9, 0xda, 0x1e, 0x9e, 0xb1, 0x3e, 0x2a, 0x8f, 
+                           0xea, 0xa5, 0x6a, 0x85, 0xd1, 0xf4, 0xa8, 0xa5 },
+               .ilen   = 32,
+               .result = { 0x54, 0x65, 0x61, 0x20, 0x69, 0x73, 0x20, 0x67, 
+                           0x6f, 0x6f, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 
+                           0x79, 0x6f, 0x75, 0x21, 0x21, 0x21, 0x20, 0x72, 
+                           0x65, 0x61, 0x6c, 0x6c, 0x79, 0x21, 0x21, 0x21 },
+               .rlen   = 32,
+       }
+};
+
 /*
  * Compression stuff.
  */
diff -urN linux/crypto/tea.c linux/crypto/tea.c
--- linux/crypto/tea.c  2004/11/19 00:28:36     1.1.2.2
+++ linux/crypto/tea.c  2005/09/23 20:41:22     1.1.2.3
@@ -1,11 +1,15 @@
 /* 
  * Cryptographic API.
  *
- * TEA and Xtended TEA Algorithms
+ * TEA, XTEA, and XETA crypto alogrithms
  *
  * The TEA and Xtended TEA algorithms were developed by David Wheeler 
  * and Roger Needham at the Computer Laboratory of Cambridge University.
  *
+ * Due to the order of evaluation in XTEA many people have incorrectly
+ * implemented it.  XETA (XTEA in the wrong order), exists for 
+ * compatibility with these implementations.
+ *
  * Copyright (c) 2004 Aaron Grothe ajgrothe@yahoo.com
  *
  * This program is free software; you can redistribute it and/or modify
@@ -153,9 +157,9 @@
        z = u32_in (src + 4);
 
        while (sum != limit) {
-               y += (z << 4 ^ z >> 5) + (z ^ sum) + ctx->KEY[sum&3]; 
+               y += ((z << 4 ^ z >> 5) + z) ^ (sum + ctx->KEY[sum&3]); 
                sum += XTEA_DELTA;
-               z += (y << 4 ^ y >> 5) + (y ^ sum) + ctx->KEY[sum>>11 &3]; 
+               z += ((y << 4 ^ y >> 5) + y) ^ (sum + ctx->KEY[sum>>11 &3]); 
        }
        
        u32_out (dst, y);
@@ -175,6 +179,51 @@
        sum = XTEA_DELTA * XTEA_ROUNDS;
 
        while (sum) {
+               z -= ((y << 4 ^ y >> 5) + y) ^ (sum + ctx->KEY[sum>>11 & 3]);
+               sum -= XTEA_DELTA;
+               y -= ((z << 4 ^ z >> 5) + z) ^ (sum + ctx->KEY[sum & 3]);
+       }
+       
+       u32_out (dst, y);
+       u32_out (dst + 4, z);
+
+}
+
+static void xeta_encrypt(void *ctx_arg, u8 *dst, const u8 *src)
+{ 
+
+       u32 y, z, sum = 0;
+       u32 limit = XTEA_DELTA * XTEA_ROUNDS;
+
+       struct xtea_ctx *ctx = ctx_arg;
+
+       y = u32_in (src);
+       z = u32_in (src + 4);
+
+       while (sum != limit) {
+               y += (z << 4 ^ z >> 5) + (z ^ sum) + ctx->KEY[sum&3];
+               sum += XTEA_DELTA;
+               z += (y << 4 ^ y >> 5) + (y ^ sum) + ctx->KEY[sum>>11 &3];
+
+       }
+       
+       u32_out (dst, y);
+       u32_out (dst + 4, z);
+
+}
+
+static void xeta_decrypt(void *ctx_arg, u8 *dst, const u8 *src)
+{ 
+
+       u32 y, z, sum;
+       struct tea_ctx *ctx = ctx_arg;
+
+       y = u32_in (src);
+       z = u32_in (src + 4);
+
+       sum = XTEA_DELTA * XTEA_ROUNDS;
+
+       while (sum) {
                z -= (y << 4 ^ y >> 5) + (y ^ sum) + ctx->KEY[sum>>11 & 3];
                sum -= XTEA_DELTA;
                y -= (z << 4 ^ z >> 5) + (z ^ sum) + ctx->KEY[sum & 3];
@@ -215,6 +264,22 @@
        .cia_decrypt            =       xtea_decrypt } }
 };
 
+
+static struct crypto_alg xeta_alg = {
+       .cra_name               =       "xeta",
+       .cra_flags              =       CRYPTO_ALG_TYPE_CIPHER,
+       .cra_blocksize          =       XTEA_BLOCK_SIZE,
+       .cra_ctxsize            =       sizeof (struct xtea_ctx),
+       .cra_module             =       THIS_MODULE,
+       .cra_list               =       LIST_HEAD_INIT(xtea_alg.cra_list),
+       .cra_u                  =       { .cipher = {
+       .cia_min_keysize        =       XTEA_KEY_SIZE,
+       .cia_max_keysize        =       XTEA_KEY_SIZE,
+       .cia_setkey             =       xtea_setkey,
+       .cia_encrypt            =       xeta_encrypt,
+       .cia_decrypt            =       xeta_decrypt } }
+};
+
 static int __init init(void)
 {
        int ret = 0;
@@ -229,6 +294,13 @@
                goto out;
        }
 
+       ret = crypto_register_alg(&xeta_alg);
+       if (ret < 0) {
+               crypto_unregister_alg(&tea_alg);
+               crypto_unregister_alg(&xtea_alg);
+               goto out;
+       }
+
 out:   
        return ret;
 }
@@ -237,10 +309,11 @@
 {
        crypto_unregister_alg(&tea_alg);
        crypto_unregister_alg(&xtea_alg);
+       crypto_unregister_alg(&xeta_alg);
 }
 
 module_init(init);
 module_exit(fini);
 
 MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("TEA & XTEA Cryptographic Algorithms");
+MODULE_DESCRIPTION("TEA, XTEA & XETA Cryptographic Algorithms");
diff -urN linux/drivers/block/cciss.c linux/drivers/block/cciss.c
--- linux/drivers/block/cciss.c 2005/05/25 17:14:23     1.12.2.13
+++ linux/drivers/block/cciss.c 2005/09/23 20:41:22     1.12.2.14
@@ -1,6 +1,6 @@
 /*
  *    Disk Array driver for HP SA 5xxx and 6xxx Controllers
- *    Copyright 2000, 2002 Hewlett-Packard Development Company, L.P. 
+ *    Copyright 2000, 2005 Hewlett-Packard Development Company, L.P. 
  *
  *    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
@@ -45,13 +45,13 @@
 #include <linux/genhd.h>
 
 #define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
-#define DRIVER_NAME "HP CISS Driver (v 2.4.52)"
-#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,4,52)
+#define DRIVER_NAME "HP CISS Driver (v 2.4.60)"
+#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,4,60)
 
 /* Embedded module documentation macros - see modules.h */
 MODULE_AUTHOR("Hewlett-Packard Company");
 MODULE_DESCRIPTION("Driver for HP SA5xxx SA6xxx Controllers version 2.4.52");
-MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400 
6i SA6422 V100"); 
+MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400 
6i SA6422 P600 P400 P400i E200i E200"); 
 MODULE_LICENSE("GPL");
 
 #include "cciss_cmd.h"
@@ -80,8 +80,24 @@
                         0x0E11, 0x4091, 0, 0, 0},
        { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC,
                         0x0E11, 0x409E, 0, 0, 0},
-       { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISS,
+       { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSA,
+                        0x103C, 0x3225, 0, 0, 0},
+       { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC,
+                        0x103C, 0x3234, 0, 0, 0},
+       { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC,
+                        0x103C, 0x3235, 0, 0, 0},
+       { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD,
                         0x103C, 0x3211, 0, 0, 0},
+       { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD,
+                        0x103C, 0x3212, 0, 0, 0},
+       { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD,
+                        0x103C, 0x3213, 0, 0, 0},
+       { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD,
+                        0x103C, 0x3214, 0, 0, 0},
+       { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD,
+                        0x103C, 0x3215, 0, 0, 0},
+       { PCI_VENDOR_ID_HP, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 
+               PCI_CLASS_STORAGE_RAID << 8, 0xffff << 8, 0},
        {0,}
 };
 MODULE_DEVICE_TABLE(pci, cciss_pci_device_id);
@@ -103,7 +119,14 @@
        { 0x409D0E11, "Smart Array 6400 EM", &SA5_access},
        { 0x40910E11, "Smart Array 6i", &SA5_access},
        { 0x409E0E11, "Smart Array 6422", &SA5_access},
-       { 0x3211103C, "Smart Array V100", &SA5_access},
+       { 0x3234103c, "Smart Array P400", &SA5_access},
+       { 0x3235103c, "Smart Array P400i", &SA5_access},
+       { 0x3211103c, "Smart Array E200i", &SA5_access},
+       { 0x3212103c, "Smart Array E200", &SA5_access},
+       { 0x3213103c, "Smart Array E200i", &SA5_access},
+       { 0x3214103c, "Smart Array E200i", &SA5_access},
+       { 0x3215103c, "Smart Array E200i", &SA5_access},
+       { 0xFFFF103C, "Unknown Smart Array", &SA5_access},
 };
 
 /* How long to wait (in millesconds) for board to go into simple mode */
@@ -2805,12 +2828,6 @@
                        break;
                }
        }
-       if (i == NR_PRODUCTS) {
-               printk(KERN_WARNING "cciss: Sorry, I don't know how"
-                       " to access the Smart Array controller %08lx\n", 
-                               (unsigned long)board_id);
-               return -1;
-       }
        if (  (readb(&c->cfgtable->Signature[0]) != 'C') ||
              (readb(&c->cfgtable->Signature[1]) != 'I') ||
              (readb(&c->cfgtable->Signature[2]) != 'S') ||
@@ -2818,6 +2835,25 @@
                printk("Does not appear to be a valid CISS config table\n");
                return -1;
        }
+       /* We didn't find the controller in our list. We know the
+        * signature is valid. If it's an HP device let's try to
+        * bind to the device and fire it up. Otherwise we bail.
+        */
+       if (i == NR_PRODUCTS) {
+               if (subsystem_vendor_id == PCI_VENDOR_ID_HP) {
+                       c->product_name = products[NR_PRODUCTS-1].product_name;
+                       c->access = *(products[NR_PRODUCTS-1].access);
+                       printk(KERN_WARNING "cciss: This is an unknown "
+                               "Smart Array controller.\n"
+                               "cciss: Please update to the latest driver "
+                               "available from www.hp.com.\n");
+               } else {
+                       printk(KERN_WARNING "cciss: Sorry, I don't know how"
+                               " to access the Smart Array controller %08lx\n"
+                                       , (unsigned long)board_id);
+                       return -1;
+               }
+       }
 
 #ifdef CONFIG_X86
 {
diff -urN linux/drivers/bluetooth/bfusb.c linux/drivers/bluetooth/bfusb.c
--- linux/drivers/bluetooth/bfusb.c     2004/08/14 18:38:49     1.1.2.3
+++ linux/drivers/bluetooth/bfusb.c     2005/09/23 20:41:22     1.1.2.4
@@ -470,12 +470,11 @@
                return 0;
 
        write_lock_irqsave(&bfusb->lock, flags);
+       write_unlock_irqrestore(&bfusb->lock, flags);
 
        bfusb_unlink_urbs(bfusb);
        bfusb_flush(hdev);
 
-       write_unlock_irqrestore(&bfusb->lock, flags);
-
        MOD_DEC_USE_COUNT;
 
        return 0;
diff -urN linux/drivers/bluetooth/hci_usb.c linux/drivers/bluetooth/hci_usb.c
--- linux/drivers/bluetooth/hci_usb.c   2004/08/14 18:38:49     1.3.2.9
+++ linux/drivers/bluetooth/hci_usb.c   2005/09/23 20:41:22     1.3.2.10
@@ -398,13 +398,13 @@
 
        BT_DBG("%s", hdev->name);
 
+       /* Synchronize with completion handlers */
        write_lock_irqsave(&husb->completion_lock, flags);
-       
+       write_unlock_irqrestore(&husb->completion_lock, flags);
+
        hci_usb_unlink_urbs(husb);
        hci_usb_flush(hdev);
 
-       write_unlock_irqrestore(&husb->completion_lock, flags);
-
        MOD_DEC_USE_COUNT;
        return 0;
 }
diff -urN linux/drivers/char/serial.c.orig linux/drivers/char/serial.c.orig
--- linux/drivers/char/Attic/serial.c.orig      1970/01/01 00:00:00
+++ linux/drivers/char/Attic/serial.c.orig      2005-09-23 21:41:22.959020000 
+0100     1.1.2.1
@@ -0,0 +1,6066 @@
+/*
+ *  linux/drivers/char/serial.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *  Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 
+ *             1998, 1999  Theodore Ts'o
+ *
+ *  Extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92.  Now
+ *  much more extensible to support other serial cards based on the
+ *  16450/16550A UART's.  Added support for the AST FourPort and the
+ *  Accent Async board.  
+ *
+ *  set_serial_info fixed to set the flags, custom divisor, and uart
+ *     type fields.  Fix suggested by Michael K. Johnson 12/12/92.
+ *
+ *  11/95: TIOCMIWAIT, TIOCGICOUNT by Angelo Haritsis <ah@doc.ic.ac.uk>
+ *
+ *  03/96: Modularised by Angelo Haritsis <ah@doc.ic.ac.uk>
+ *
+ *  rs_set_termios fixed to look also for changes of the input
+ *      flags INPCK, BRKINT, PARMRK, IGNPAR and IGNBRK.
+ *                                            Bernd Anhäupl 05/17/96.
+ *
+ *  1/97:  Extended dumb serial ports are a config option now.  
+ *         Saves 4k.   Michael A. Griffith <grif@acm.org>
+ * 
+ *  8/97: Fix bug in rs_set_termios with RTS
+ *        Stanislav V. Voronyi <stas@uanet.kharkov.ua>
+ *
+ *  3/98: Change the IRQ detection, use of probe_irq_o*(),
+ *       suppress TIOCSERGWILD and TIOCSERSWILD
+ *       Etienne Lorrain <etienne.lorrain@ibm.net>
+ *
+ *  4/98: Added changes to support the ARM architecture proposed by
+ *       Russell King
+ *
+ *  5/99: Updated to include support for the XR16C850 and ST16C654
+ *        uarts.  Stuart MacDonald <stuartm@connecttech.com>
+ *
+ *  8/99: Generalized PCI support added.  Theodore Ts'o
+ * 
+ *  3/00: Rid circular buffer of redundant xmit_cnt.  Fix a
+ *       few races on freeing buffers too.
+ *       Alan Modra <alan@linuxcare.com>
+ *
+ *  5/00: Support for the RSA-DV II/S card added.
+ *       Kiyokazu SUTO <suto@ks-and-ks.ne.jp>
+ * 
+ *  6/00: Remove old-style timer, use timer_list
+ *        Andrew Morton <andrewm@uow.edu.au>
+ *
+ *  7/00: Support Timedia/Sunix/Exsys PCI cards
+ *
+ *  7/00: fix some returns on failure not using MOD_DEC_USE_COUNT.
+ *       Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ *
+ * 10/00: add in optional software flow control for serial console.
+ *       Kanoj Sarcar <kanoj@sgi.com>  (Modified by Theodore Ts'o)
+ *
+ * 02/02: Fix for AMD Elan bug in transmit irq routine, by
+ *        Christer Weinigel <wingel@hog.ctrl-c.liu.se>,
+ *        Robert Schwebel <robert@schwebel.de>,
+ *        Juergen Beisert <jbeisert@eurodsn.de>,
+ *        Theodore Ts'o <tytso@mit.edu>
+ *
+ * 10/00: Added suport for MIPS Atlas board.
+ * 11/00: Hooks for serial kernel debug port support added.
+ *        Kevin D. Kissell, kevink@mips.com and Carsten Langgaard,
+ *        carstenl@mips.com
+ *        Copyright (C) 2000 MIPS Technologies, Inc.  All rights reserved.
+ */
+
+static char *serial_version = "5.05c";
+static char *serial_revdate = "2001-07-08";
+
+/*
+ * Serial driver configuration section.  Here are the various options:
+ *
+ * CONFIG_HUB6
+ *             Enables support for the venerable Bell Technologies
+ *             HUB6 card.
+ *
+ * CONFIG_SERIAL_MANY_PORTS
+ *             Enables support for ports beyond the standard, stupid
+ *             COM 1/2/3/4.
+ *
+ * CONFIG_SERIAL_MULTIPORT
+ *             Enables support for special multiport board support.
+ *
+ * CONFIG_SERIAL_SHARE_IRQ
+ *             Enables support for multiple serial ports on one IRQ
+ *
+ * CONFIG_SERIAL_DETECT_IRQ
+ *             Enable the autodetection of IRQ on standart ports
+ *
+ * SERIAL_PARANOIA_CHECK
+ *             Check the magic number for the async_structure where
+ *             ever possible.
+ *
+ * CONFIG_SERIAL_ACPI
+ *             Enable support for serial console port and serial 
+ *             debug port as defined by the SPCR and DBGP tables in 
+ *             ACPI 2.0.
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+
+#undef SERIAL_PARANOIA_CHECK
+#define CONFIG_SERIAL_NOPAUSE_IO
+#define SERIAL_DO_RESTART
+
+#if 0
+/* These defines are normally controlled by the autoconf.h */
+#define CONFIG_SERIAL_MANY_PORTS
+#define CONFIG_SERIAL_SHARE_IRQ
+#define CONFIG_SERIAL_DETECT_IRQ
+#define CONFIG_SERIAL_MULTIPORT
+#define CONFIG_HUB6
+#endif
+
+#ifdef CONFIG_PCI
+#define ENABLE_SERIAL_PCI
+#ifndef CONFIG_SERIAL_SHARE_IRQ
+#define CONFIG_SERIAL_SHARE_IRQ
+#endif
+#ifndef CONFIG_SERIAL_MANY_PORTS
+#define CONFIG_SERIAL_MANY_PORTS
+#endif
+#endif
+
+#ifdef CONFIG_SERIAL_ACPI
+#define ENABLE_SERIAL_ACPI
+#endif
+
+#if defined(CONFIG_ISAPNP)|| (defined(CONFIG_ISAPNP_MODULE) && defined(MODULE))
+#ifndef ENABLE_SERIAL_PNP
+#define ENABLE_SERIAL_PNP
+#endif
+#endif
+
+/* Set of debugging defines */
+
+#undef SERIAL_DEBUG_INTR
+#undef SERIAL_DEBUG_OPEN
+#undef SERIAL_DEBUG_FLOW
+#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+#undef SERIAL_DEBUG_PCI
+#undef SERIAL_DEBUG_AUTOCONF
+
+/* Sanity checks */
+
+#ifdef CONFIG_SERIAL_MULTIPORT
+#ifndef CONFIG_SERIAL_SHARE_IRQ
+#define CONFIG_SERIAL_SHARE_IRQ
+#endif
+#endif
+
+#ifdef CONFIG_HUB6
+#ifndef CONFIG_SERIAL_MANY_PORTS
+#define CONFIG_SERIAL_MANY_PORTS
+#endif
+#ifndef CONFIG_SERIAL_SHARE_IRQ
+#define CONFIG_SERIAL_SHARE_IRQ
+#endif
+#endif
+
+#ifdef MODULE
+#undef CONFIG_SERIAL_CONSOLE
+#endif
+
+#define CONFIG_SERIAL_RSA
+
+#define RS_STROBE_TIME (10*HZ)
+#define RS_ISR_PASS_LIMIT 256
+
+#if defined(__i386__) && (defined(CONFIG_M386) || defined(CONFIG_M486))
+#define SERIAL_INLINE
+#endif
+  
+/*
+ * End of serial driver configuration section.
+ */
+
+#include <linux/module.h>
+
+#include <linux/types.h>
+#ifdef LOCAL_HEADERS
+#include "serial_local.h"
+#else
+#include <linux/serial.h>
+#include <linux/serialP.h>
+#include <linux/serial_reg.h>
+#include <asm/serial.h>
+#define LOCAL_VERSTRING ""
+#endif
+
+#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/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#if (LINUX_VERSION_CODE >= 131343)
+#include <linux/init.h>
+#endif
+#if (LINUX_VERSION_CODE >= 131336)
+#include <asm/uaccess.h>
+#endif
+#include <linux/delay.h>
+#ifdef CONFIG_SERIAL_CONSOLE
+#include <linux/console.h>
+#endif
+#ifdef ENABLE_SERIAL_PCI
+#include <linux/pci.h>
+#endif
+#ifdef ENABLE_SERIAL_PNP
+#include <linux/isapnp.h>
+#endif
+#ifdef CONFIG_MAGIC_SYSRQ
+#include <linux/sysrq.h>
+#endif
+
+/*
+ * All of the compatibilty code so we can compile serial.c against
+ * older kernels is hidden in serial_compat.h
+ */
+#if defined(LOCAL_HEADERS) || (LINUX_VERSION_CODE < 0x020317) /* 2.3.23 */
+#include "serial_compat.h"
+#endif
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/bitops.h>
+
+#if defined(CONFIG_MAC_SERIAL)
+#define SERIAL_DEV_OFFSET      ((_machine == _MACH_prep || _machine == 
_MACH_chrp) ? 0 : 2)
+#else
+#define SERIAL_DEV_OFFSET      0
+#endif
+
+#ifdef SERIAL_INLINE
+#define _INLINE_ inline
+#else
+#define _INLINE_
+#endif
+
+static char *serial_name = "Serial driver";
+
+static DECLARE_TASK_QUEUE(tq_serial);
+
+static struct tty_driver serial_driver, callout_driver;
+static int serial_refcount;
+
+static struct timer_list serial_timer;
+
+/* serial subtype definitions */
+#ifndef SERIAL_TYPE_NORMAL
+#define SERIAL_TYPE_NORMAL     1
+#define SERIAL_TYPE_CALLOUT    2
+#endif
+
+/* number of characters left in xmit buffer before we ask for more */
+#define WAKEUP_CHARS 256
+
+/*
+ * IRQ_timeout         - How long the timeout should be for each IRQ
+ *                             should be after the IRQ has been active.
+ */
+
+static struct async_struct *IRQ_ports[NR_IRQS];
+#ifdef CONFIG_SERIAL_MULTIPORT
+static struct rs_multiport_struct rs_multiport[NR_IRQS];
+#endif
+static int IRQ_timeout[NR_IRQS];
+#ifdef CONFIG_SERIAL_CONSOLE
+static struct console sercons;
+static int lsr_break_flag;
+#endif
+#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+static unsigned long break_pressed; /* break, really ... */
+#endif
+
+static unsigned detect_uart_irq (struct serial_state * state);
+static void autoconfig(struct serial_state * state);
+static void change_speed(struct async_struct *info, struct termios *old);
+static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
+
+/*
+ * Here we define the default xmit fifo size used for each type of
+ * UART
+ */
+static struct serial_uart_config uart_config[] = {
+       { "unknown", 1, 0 }, 
+       { "8250", 1, 0 }, 
+       { "16450", 1, 0 }, 
+       { "16550", 1, 0 }, 
+       { "16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO }, 
+       { "cirrus", 1, 0 },     /* usurped by cyclades.c */
+       { "ST16650", 1, UART_CLEAR_FIFO | UART_STARTECH }, 
+       { "ST16650V2", 32, UART_CLEAR_FIFO | UART_USE_FIFO |
+                 UART_STARTECH }, 
+       { "TI16750", 64, UART_CLEAR_FIFO | UART_USE_FIFO},
+       { "Startech", 1, 0},    /* usurped by cyclades.c */
+       { "16C950/954", 128, UART_CLEAR_FIFO | UART_USE_FIFO},
+       { "ST16654", 64, UART_CLEAR_FIFO | UART_USE_FIFO |
+                 UART_STARTECH }, 
+       { "XR16850", 128, UART_CLEAR_FIFO | UART_USE_FIFO |
+                 UART_STARTECH },
+       { "RSA", 2048, UART_CLEAR_FIFO | UART_USE_FIFO }, 
+       { 0, 0}
+};
+
+#if defined(CONFIG_SERIAL_RSA) && defined(MODULE)
+
+#define PORT_RSA_MAX 4
+static int probe_rsa[PORT_RSA_MAX];
+static int force_rsa[PORT_RSA_MAX];
+
+MODULE_PARM(probe_rsa, "1-" __MODULE_STRING(PORT_RSA_MAX) "i");
+MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA");
+MODULE_PARM(force_rsa, "1-" __MODULE_STRING(PORT_RSA_MAX) "i");
+MODULE_PARM_DESC(force_rsa, "Force I/O ports for RSA");
+#endif /* CONFIG_SERIAL_RSA  */
+
+struct serial_state rs_table[RS_TABLE_SIZE] = {
+       SERIAL_PORT_DFNS        /* Defined in serial.h */
+};
+
+#define NR_PORTS       (sizeof(rs_table)/sizeof(struct serial_state))
+int serial_nr_ports = NR_PORTS;
+
+#if (defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP))
+#define NR_PCI_BOARDS  8
+
+static struct pci_board_inst   serial_pci_board[NR_PCI_BOARDS];
+
+#ifndef IS_PCI_REGION_IOPORT
+#define IS_PCI_REGION_IOPORT(dev, r) (pci_resource_flags((dev), (r)) & \
+                                     IORESOURCE_IO)
+#endif
+#ifndef IS_PCI_REGION_IOMEM
+#define IS_PCI_REGION_IOMEM(dev, r) (pci_resource_flags((dev), (r)) & \
+                                     IORESOURCE_MEM)
+#endif
+#ifndef PCI_IRQ_RESOURCE
+#define PCI_IRQ_RESOURCE(dev, r) ((dev)->irq_resource[r].start)
+#endif
+#ifndef pci_get_subvendor
+#define pci_get_subvendor(dev) ((dev)->subsystem_vendor)
+#define pci_get_subdevice(dev)  ((dev)->subsystem_device)
+#endif
+#endif /* ENABLE_SERIAL_PCI || ENABLE_SERIAL_PNP  */
+
+#ifndef PREPARE_FUNC
+#define PREPARE_FUNC(dev)  (dev->prepare)
+#define ACTIVATE_FUNC(dev)  (dev->activate)
+#define DEACTIVATE_FUNC(dev)  (dev->deactivate)
+#endif
+
+#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
+
+static struct tty_struct *serial_table[NR_PORTS];
+static struct termios *serial_termios[NR_PORTS];
+static struct termios *serial_termios_locked[NR_PORTS];
+
+
+#if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT)
+#define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \
+ kdevname(tty->device), (info->flags), 
serial_refcount,info->count,tty->count,s)
+#else
+#define DBG_CNT(s)
+#endif
+
+/*
+ * tmp_buf is used as a temporary buffer by serial_write.  We need to
+ * lock it in case the copy_from_user 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 *tmp_buf;
+#ifdef DECLARE_MUTEX
+static DECLARE_MUTEX(tmp_buf_sem);
+#else
+static struct semaphore tmp_buf_sem = MUTEX;
+#endif
+
+
+static inline int serial_paranoia_check(struct async_struct *info,
+                                       kdev_t device, const char *routine)
+{
+#ifdef SERIAL_PARANOIA_CHECK
+       static const char *badmagic =
+               "Warning: bad magic number for serial struct (%s) in %s\n";
+       static const char *badinfo =
+               "Warning: null async_struct for (%s) in %s\n";
+
+       if (!info) {
+               printk(badinfo, kdevname(device), routine);
+               return 1;
+       }
+       if (info->magic != SERIAL_MAGIC) {
+               printk(badmagic, kdevname(device), routine);
+               return 1;
+       }
+#endif
+       return 0;
+}
+
+#if defined(CONFIG_MIPS_ATLAS) || defined(CONFIG_MIPS_SEAD)
+
+#include <asm/mips-boards/atlas.h>
+
+static _INLINE_ unsigned int serial_in(struct async_struct *info, int offset)
+{
+        return (*(volatile unsigned int *)(mips_io_port_base + 
ATLAS_UART_REGS_BASE + offset*8) & 0xff);
+}
+
+static _INLINE_ void serial_out(struct async_struct *info, int offset, int 
value)
+{
+        *(volatile unsigned int *)(mips_io_port_base + ATLAS_UART_REGS_BASE + 
offset*8) = value;
+}
+
+#else
+
+static _INLINE_ unsigned int serial_in(struct async_struct *info, int offset)
+{
+       switch (info->io_type) {
+#ifdef CONFIG_HUB6
+       case SERIAL_IO_HUB6:
+               outb(info->hub6 - 1 + offset, info->port);
+               return inb(info->port+1);
+#endif
+       case SERIAL_IO_MEM:
+               return readb((unsigned long) info->iomem_base +
+                            (offset<<info->iomem_reg_shift));
+       default:
+               return inb(info->port + offset);
+       }
+}
+
+static _INLINE_ void serial_out(struct async_struct *info, int offset,
+                               int value)
+{
+       switch (info->io_type) {
+#ifdef CONFIG_HUB6
+       case SERIAL_IO_HUB6:
+               outb(info->hub6 - 1 + offset, info->port);
+               outb(value, info->port+1);
+               break;
+#endif
+       case SERIAL_IO_MEM:
+               writeb(value, (unsigned long) info->iomem_base +
+                             (offset<<info->iomem_reg_shift));
+               break;
+       default:
+               outb(value, info->port+offset);
+       }
+}
+#endif
+
+
+/*
+ * We used to support using pause I/O for certain machines.  We
+ * haven't supported this for a while, but just in case it's badly
+ * needed for certain old 386 machines, I've left these #define's
+ * in....
+ */
+#define serial_inp(info, offset)               serial_in(info, offset)
+#define serial_outp(info, offset, value)       serial_out(info, offset, value)
+
+
+/*
+ * For the 16C950
+ */
+void serial_icr_write(struct async_struct *info, int offset, int  value)
+{
+       serial_out(info, UART_SCR, offset);
+       serial_out(info, UART_ICR, value);
+}
+
+unsigned int serial_icr_read(struct async_struct *info, int offset)
+{
+       int     value;
+
+       serial_icr_write(info, UART_ACR, info->ACR | UART_ACR_ICRRD);
+       serial_out(info, UART_SCR, offset);
+       value = serial_in(info, UART_ICR);
+       serial_icr_write(info, UART_ACR, info->ACR);
+       return value;
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_stop() and rs_start()
+ *
+ * This routines are called before setting or resetting tty->stopped.
+ * They enable or disable transmitter interrupts, as necessary.
+ * ------------------------------------------------------------
+ */
+static void rs_stop(struct tty_struct *tty)
+{
+       struct async_struct *info = (struct async_struct *)tty->driver_data;
+       unsigned long flags;
+
+       if (serial_paranoia_check(info, tty->device, "rs_stop"))
+               return;
+       
+       save_flags(flags); cli();
+       if (info->IER & UART_IER_THRI) {
+               info->IER &= ~UART_IER_THRI;
+               serial_out(info, UART_IER, info->IER);
+       }
+       if (info->state->type == PORT_16C950) {
+               info->ACR |= UART_ACR_TXDIS;
+               serial_icr_write(info, UART_ACR, info->ACR);
+       }
+       restore_flags(flags);
+}
+
+static void rs_start(struct tty_struct *tty)
+{
+       struct async_struct *info = (struct async_struct *)tty->driver_data;
+       unsigned long flags;
+       
+       if (serial_paranoia_check(info, tty->device, "rs_start"))
+               return;
+       
+       save_flags(flags); cli();
+       if (info->xmit.head != info->xmit.tail
+           && info->xmit.buf
+           && !(info->IER & UART_IER_THRI)) {
+               info->IER |= UART_IER_THRI;
+               serial_out(info, UART_IER, info->IER);
+       }
+       if (info->state->type == PORT_16C950) {
+               info->ACR &= ~UART_ACR_TXDIS;
+               serial_icr_write(info, UART_ACR, info->ACR);
+       }
+       restore_flags(flags);
+}
+
+/*
+ * ----------------------------------------------------------------------
+ *
+ * Here starts the interrupt handling routines.  All of the following
+ * subroutines are declared as inline and are folded into
+ * rs_interrupt().  They were separated out for readability's sake.
+ *
+ * Note: rs_interrupt() is a "fast" interrupt, which means that it
+ * runs with interrupts turned off.  People who may want to modify
+ * rs_interrupt() should try to keep the interrupt handler as fast as
+ * possible.  After you are done making modifications, it is not a bad
+ * idea to do:
+ * 
+ * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
+ *
+ * and look at the resulting assemble code in serial.s.
+ *
+ *                             - Ted Ts'o (tytso@mit.edu), 7-Mar-93
+ * -----------------------------------------------------------------------
+ */
+
+/*
+ * This routine is used by the interrupt handler to schedule
+ * processing in the software interrupt portion of the driver.
+ */
+static _INLINE_ void rs_sched_event(struct async_struct *info,
+                                 int event)
+{
+       info->event |= 1 << event;
+       queue_task(&info->tqueue, &tq_serial);
+       mark_bh(SERIAL_BH);
+}
+
+static _INLINE_ void receive_chars(struct async_struct *info,
+                                int *status, struct pt_regs * regs)
+{
+       struct tty_struct *tty = info->tty;
+       unsigned char ch;
+       struct  async_icount *icount;
+       int     max_count = 256;
+
+       icount = &info->state->icount;
+       do {
+               if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+                       tty->flip.tqueue.routine((void *) tty);
+                       if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+                               /* no room in flip buffer, discard rx FIFO 
contents to clear IRQ
+                                * *FIXME* Hardware with auto flow control
+                                * would benefit from leaving the data in the 
FIFO and
+                                * disabling the rx IRQ until space becomes 
available.
+                                */
+                               do {
+                                       serial_inp(info, UART_RX);
+                                       icount->overrun++;
+                                       *status = serial_inp(info, UART_LSR);
+                               } while ((*status & UART_LSR_DR) && 
(max_count-- > 0));
+                               return;         // if TTY_DONT_FLIP is set
+                       }
+               }
+               ch = serial_inp(info, UART_RX);
+               *tty->flip.char_buf_ptr = ch;
+               icount->rx++;
+               
+#ifdef SERIAL_DEBUG_INTR
+               printk("DR%02x:%02x...", ch, *status);
+#endif
+               *tty->flip.flag_buf_ptr = 0;
+               if (*status & (UART_LSR_BI | UART_LSR_PE |
+                              UART_LSR_FE | UART_LSR_OE)) {
+                       /*
+                        * For statistics only
+                        */
+                       if (*status & UART_LSR_BI) {
+                               *status &= ~(UART_LSR_FE | UART_LSR_PE);
+                               icount->brk++;
+                               /*
+                                * We do the SysRQ and SAK checking
+                                * here because otherwise the break
+                                * may get masked by ignore_status_mask
+                                * or read_status_mask.
+                                */
+#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+                               if (info->line == sercons.index) {
+                                       if (!break_pressed) {
+                                               break_pressed = jiffies;
+                                               goto ignore_char;
+                                       }
+                                       break_pressed = 0;
+                               }
+#endif
+                               if (info->flags & ASYNC_SAK)
+                                       do_SAK(tty);
+                       } else if (*status & UART_LSR_PE)
+                               icount->parity++;
+                       else if (*status & UART_LSR_FE)
+                               icount->frame++;
+                       if (*status & UART_LSR_OE)
+                               icount->overrun++;
+
+                       /*
+                        * Mask off conditions which should be ignored.
+                        */
+                       *status &= info->read_status_mask;
+
+#ifdef CONFIG_SERIAL_CONSOLE
+                       if (info->line == sercons.index) {
+                               /* Recover the break flag from console xmit */
+                               *status |= lsr_break_flag;
+                               lsr_break_flag = 0;
+                       }
+#endif
+                       if (*status & (UART_LSR_BI)) {
+#ifdef SERIAL_DEBUG_INTR
+                               printk("handling break....");
+#endif
+                               *tty->flip.flag_buf_ptr = TTY_BREAK;
+                       } 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;
+               }
+#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+               if (break_pressed && info->line == sercons.index) {
+                       if (ch != 0 &&
+                           time_before(jiffies, break_pressed + HZ*5)) {
+                               handle_sysrq(ch, regs, NULL, NULL);
+                               break_pressed = 0;
+                               goto ignore_char;
+                       }
+                       break_pressed = 0;
+               }
+#endif
+               if ((*status & info->ignore_status_mask) == 0) {
+                       tty->flip.flag_buf_ptr++;
+                       tty->flip.char_buf_ptr++;
+                       tty->flip.count++;
+               }
+               if ((*status & UART_LSR_OE) &&
+                   (tty->flip.count < TTY_FLIPBUF_SIZE)) {
+                       /*
+                        * Overrun is special, since it's reported
+                        * immediately, and doesn't affect the current
+                        * character
+                        */
+                       *tty->flip.flag_buf_ptr = TTY_OVERRUN;
+                       tty->flip.count++;
+                       tty->flip.flag_buf_ptr++;
+                       tty->flip.char_buf_ptr++;
+               }
+#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+       ignore_char:
+#endif
+               *status = serial_inp(info, UART_LSR);
+       } while ((*status & UART_LSR_DR) && (max_count-- > 0));
+#if (LINUX_VERSION_CODE > 131394) /* 2.1.66 */
+       tty_flip_buffer_push(tty);
+#else
+       queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
+#endif 
+}
+
+static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done)
+{
+       int count;
+
+       if (info->x_char) {
+               serial_outp(info, UART_TX, info->x_char);
+               info->state->icount.tx++;
+               info->x_char = 0;
+               if (intr_done)
+                       *intr_done = 0;
+               return;
+       }
+       if (info->xmit.head == info->xmit.tail
+           || info->tty->stopped
+           || info->tty->hw_stopped) {
+               info->IER &= ~UART_IER_THRI;
+               serial_out(info, UART_IER, info->IER);
+               return;
+       }
+       
+       count = info->xmit_fifo_size;
+       do {
+               serial_out(info, UART_TX, info->xmit.buf[info->xmit.tail]);
+               info->xmit.tail = (info->xmit.tail + 1) & (SERIAL_XMIT_SIZE-1);
+               info->state->icount.tx++;
+               if (info->xmit.head == info->xmit.tail)
+                       break;
+       } while (--count > 0);
+       
+       if (CIRC_CNT(info->xmit.head,
+                    info->xmit.tail,
+                    SERIAL_XMIT_SIZE) < WAKEUP_CHARS)
+               rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+
+#ifdef SERIAL_DEBUG_INTR
+       printk("THRE...");
+#endif
+       if (intr_done)
+               *intr_done = 0;
+
+       if (info->xmit.head == info->xmit.tail) {
+               info->IER &= ~UART_IER_THRI;
+               serial_out(info, UART_IER, info->IER);
+       }
+}
+
+static _INLINE_ void check_modem_status(struct async_struct *info)
+{
+       int     status;
+       struct  async_icount *icount;
+       
+       status = serial_in(info, UART_MSR);
+
+       if (status & UART_MSR_ANY_DELTA) {
+               icount = &info->state->icount;
+               /* update input line counters */
+               if (status & UART_MSR_TERI)
+                       icount->rng++;
+               if (status & UART_MSR_DDSR)
+                       icount->dsr++;
+               if (status & UART_MSR_DDCD) {
+                       icount->dcd++;
+#ifdef CONFIG_HARD_PPS
+                       if ((info->flags & ASYNC_HARDPPS_CD) &&
+                           (status & UART_MSR_DCD))
+                               hardpps();
+#endif
+               }
+               if (status & UART_MSR_DCTS)
+                       icount->cts++;
+               wake_up_interruptible(&info->delta_msr_wait);
+       }
+
+       if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
+#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
+               printk("ttys%d CD now %s...", info->line,
+                      (status & UART_MSR_DCD) ? "on" : "off");
+#endif         
+               if (status & UART_MSR_DCD)
+                       wake_up_interruptible(&info->open_wait);
+               else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+                          (info->flags & ASYNC_CALLOUT_NOHUP))) {
+#ifdef SERIAL_DEBUG_OPEN
+                       printk("doing serial hangup...");
+#endif
+                       if (info->tty)
+                               tty_hangup(info->tty);
+               }
+       }
+       if (info->flags & ASYNC_CTS_FLOW) {
+               if (info->tty->hw_stopped) {
+                       if (status & UART_MSR_CTS) {
+#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
+                               printk("CTS tx start...");
+#endif
+                               info->tty->hw_stopped = 0;
+                               info->IER |= UART_IER_THRI;
+                               serial_out(info, UART_IER, info->IER);
+                               rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+                               return;
+                       }
+               } else {
+                       if (!(status & UART_MSR_CTS)) {
+#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
+                               printk("CTS tx stop...");
+#endif
+                               info->tty->hw_stopped = 1;
+                               info->IER &= ~UART_IER_THRI;
+                               serial_out(info, UART_IER, info->IER);
+                       }
+               }
+       }
+}
+
+#ifdef CONFIG_SERIAL_SHARE_IRQ
+/*
+ * This is the serial driver's generic interrupt routine
+ */
+static void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+       int status, iir;
+       struct async_struct * info;
+       int pass_counter = 0;
+       struct async_struct *end_mark = 0;
+#ifdef CONFIG_SERIAL_MULTIPORT 
+       int first_multi = 0;
+       struct rs_multiport_struct *multi;
+#endif
+
+#ifdef SERIAL_DEBUG_INTR
+       printk("rs_interrupt(%d)...", irq);
+#endif
+
+       info = IRQ_ports[irq];
+       if (!info)
+               return;
+
+#ifdef CONFIG_SERIAL_MULTIPORT 
+       multi = &rs_multiport[irq];
+       if (multi->port_monitor)
+               first_multi = inb(multi->port_monitor);
+#endif
+
+       do {
+               if (!info->tty ||
+                   ((iir=serial_in(info, UART_IIR)) & UART_IIR_NO_INT)) {
+                       if (!end_mark)
+                               end_mark = info;
+                       goto next;
+               }
+#ifdef SERIAL_DEBUG_INTR
+               printk("IIR = %x...", serial_in(info, UART_IIR));
+#endif
+               end_mark = 0;
+
+               info->last_active = jiffies;
+
+               status = serial_inp(info, UART_LSR);
+#ifdef SERIAL_DEBUG_INTR
+               printk("status = %x...", status);
+#endif
+               if (status & UART_LSR_DR)
+                       receive_chars(info, &status, regs);
+               check_modem_status(info);
+#ifdef CONFIG_MELAN
+               if ((status & UART_LSR_THRE) ||
+                       /* for buggy ELAN processors */
+                       ((iir & UART_IIR_ID) == UART_IIR_THRI))
+                       transmit_chars(info, 0);
+#else
+               if (status & UART_LSR_THRE)
+                       transmit_chars(info, 0);
+#endif
+
+       next:
+               info = info->next_port;
+               if (!info) {
+                       info = IRQ_ports[irq];
+                       if (pass_counter++ > RS_ISR_PASS_LIMIT) {
+#if 0
+                               printk("rs loop break\n");
+#endif
+                               break;  /* Prevent infinite loops */
+                       }
+                       continue;
+               }
+       } while (end_mark != info);
+#ifdef CONFIG_SERIAL_MULTIPORT 
+       if (multi->port_monitor)
+               printk("rs port monitor (normal) irq %d: 0x%x, 0x%x\n",
+                      info->state->irq, first_multi,
+                      inb(multi->port_monitor));
+#endif
+#ifdef SERIAL_DEBUG_INTR
+       printk("end.\n");
+#endif
+}
+#endif /* #ifdef CONFIG_SERIAL_SHARE_IRQ */
+
+
+/*
+ * This is the serial driver's interrupt routine for a single port
+ */
+static void rs_interrupt_single(int irq, void *dev_id, struct pt_regs * regs)
+{
+       int status, iir;
+       int pass_counter = 0;
+       struct async_struct * info;
+#ifdef CONFIG_SERIAL_MULTIPORT 
+       int first_multi = 0;
+       struct rs_multiport_struct *multi;
+#endif
+       
+#ifdef SERIAL_DEBUG_INTR
+       printk("rs_interrupt_single(%d)...", irq);
+#endif
+
+       info = IRQ_ports[irq];
+       if (!info || !info->tty)
+               return;
+
+#ifdef CONFIG_SERIAL_MULTIPORT 
+       multi = &rs_multiport[irq];
+       if (multi->port_monitor)
+               first_multi = inb(multi->port_monitor);
+#endif
+
+       iir = serial_in(info, UART_IIR);
+       do {
+               status = serial_inp(info, UART_LSR);
+#ifdef SERIAL_DEBUG_INTR
+               printk("status = %x...", status);
+#endif
+               if (status & UART_LSR_DR)
+                       receive_chars(info, &status, regs);
+               check_modem_status(info);
+#ifdef CONFIG_MELAN
+               if ((status & UART_LSR_THRE) ||
+                   /* For buggy ELAN processors */
+                   ((iir & UART_IIR_ID) == UART_IIR_THRI))
+                       transmit_chars(info, 0);
+#else
+               if (status & UART_LSR_THRE)
+                       transmit_chars(info, 0);
+#endif
+               if (pass_counter++ > RS_ISR_PASS_LIMIT) {
+#if SERIAL_DEBUG_INTR
+                       printk("rs_single loop break.\n");
+#endif
+                       break;
+               }
+               iir = serial_in(info, UART_IIR);
+#ifdef SERIAL_DEBUG_INTR
+               printk("IIR = %x...", iir);
+#endif
+       } while ((iir & UART_IIR_NO_INT) == 0);
+       info->last_active = jiffies;
+#ifdef CONFIG_SERIAL_MULTIPORT 
+       if (multi->port_monitor)
+               printk("rs port monitor (single) irq %d: 0x%x, 0x%x\n",
+                      info->state->irq, first_multi,
+                      inb(multi->port_monitor));
+#endif
+#ifdef SERIAL_DEBUG_INTR
+       printk("end.\n");
+#endif
+}
+
+#ifdef CONFIG_SERIAL_MULTIPORT 
+/*
+ * This is the serial driver's for multiport boards
+ */
+static void rs_interrupt_multi(int irq, void *dev_id, struct pt_regs * regs)
+{
+       int status;
+       struct async_struct * info;
+       int pass_counter = 0;
+       int first_multi= 0;
+       struct rs_multiport_struct *multi;
+
+#ifdef SERIAL_DEBUG_INTR
+       printk("rs_interrupt_multi(%d)...", irq);
+#endif
+
+       info = IRQ_ports[irq];
+       if (!info)
+               return;
+       multi = &rs_multiport[irq];
+       if (!multi->port1) {
+               /* Should never happen */
+               printk("rs_interrupt_multi: NULL port1!\n");
+               return;
+       }
+       if (multi->port_monitor)
+               first_multi = inb(multi->port_monitor);
+       
+       while (1) {
+               if (!info->tty ||
+                   (serial_in(info, UART_IIR) & UART_IIR_NO_INT))
+                       goto next;
+
+               info->last_active = jiffies;
+
+               status = serial_inp(info, UART_LSR);
+#ifdef SERIAL_DEBUG_INTR
+               printk("status = %x...", status);
+#endif
+               if (status & UART_LSR_DR)
+                       receive_chars(info, &status, regs);
+               check_modem_status(info);
+               if (status & UART_LSR_THRE)
+                       transmit_chars(info, 0);
+
+       next:
+               info = info->next_port;
+               if (info)
+                       continue;
+
+               info = IRQ_ports[irq];
+               /*
+                * The user was a bonehead, and misconfigured their
+                * multiport info.  Rather than lock up the kernel
+                * in an infinite loop, if we loop too many times,
+                * print a message and break out of the loop.
+                */
+               if (pass_counter++ > RS_ISR_PASS_LIMIT) {
+                       printk("Misconfigured multiport serial info "
+                              "for irq %d.  Breaking out irq loop\n", irq);
+                       break; 
+               }
+               if (multi->port_monitor)
+                       printk("rs port monitor irq %d: 0x%x, 0x%x\n",
+                              info->state->irq, first_multi,
+                              inb(multi->port_monitor));
+               if ((inb(multi->port1) & multi->mask1) != multi->match1)
+                       continue;
+               if (!multi->port2)
+                       break;
+               if ((inb(multi->port2) & multi->mask2) != multi->match2)
+                       continue;
+               if (!multi->port3)
+                       break;
+               if ((inb(multi->port3) & multi->mask3) != multi->match3)
+                       continue;
+               if (!multi->port4)
+                       break;
+               if ((inb(multi->port4) & multi->mask4) != multi->match4)
+                       continue;
+               break;
+       } 
+#ifdef SERIAL_DEBUG_INTR
+       printk("end.\n");
+#endif
+}
+#endif
+
+/*
+ * -------------------------------------------------------------------
+ * Here ends the serial interrupt routines.
+ * -------------------------------------------------------------------
+ */
+
+/*
+ * This routine is used to handle the "bottom half" processing for the
+ * serial driver, known also the "software interrupt" processing.
+ * This processing is done at the kernel interrupt level, after the
+ * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON.  This
+ * is where time-consuming activities which can not be done in the
+ * interrupt driver proper are done; the interrupt driver schedules
+ * them using rs_sched_event(), and they get done here.
+ */
+static void do_serial_bh(void)
+{
+       run_task_queue(&tq_serial);
+}
+
+static void do_softint(void *private_)
+{
+       struct async_struct     *info = (struct async_struct *) private_;
+       struct tty_struct       *tty;
+
+       tty = info->tty;
+       if (!tty)
+               return;
+
+       if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
+               tty_wakeup(tty);
+               
+#ifdef SERIAL_HAVE_POLL_WAIT
+               wake_up_interruptible(&tty->poll_wait);
+#endif
+       }
+}
+
+/*
+ * This subroutine is called when the RS_TIMER goes off.  It is used
+ * by the serial driver to handle ports that do not have an interrupt
+ * (irq=0).  This doesn't work very well for 16450's, but gives barely
+ * passable results for a 16550A.  (Although at the expense of much
+ * CPU overhead).
+ */
+static void rs_timer(unsigned long dummy)
+{
+       static unsigned long last_strobe;
+       struct async_struct *info;
+       unsigned int    i;
+       unsigned long flags;
+
+       if ((jiffies - last_strobe) >= RS_STROBE_TIME) {
+               for (i=0; i < NR_IRQS; i++) {
+                       info = IRQ_ports[i];
+                       if (!info)
+                               continue;
+                       save_flags(flags); cli();
+#ifdef CONFIG_SERIAL_SHARE_IRQ
+                       if (info->next_port) {
+                               do {
+                                       serial_out(info, UART_IER, 0);
+                                       info->IER |= UART_IER_THRI;
+                                       serial_out(info, UART_IER, info->IER);
+                                       info = info->next_port;
+                               } while (info);
+#ifdef CONFIG_SERIAL_MULTIPORT
+                               if (rs_multiport[i].port1)
+                                       rs_interrupt_multi(i, NULL, NULL);
+                               else
+#endif
+                                       rs_interrupt(i, NULL, NULL);
+                       } else
+#endif /* CONFIG_SERIAL_SHARE_IRQ */
+                               rs_interrupt_single(i, NULL, NULL);
+                       restore_flags(flags);
+               }
+       }
+       last_strobe = jiffies;
+       mod_timer(&serial_timer, jiffies + RS_STROBE_TIME);
+
+       if (IRQ_ports[0]) {
+               save_flags(flags); cli();
+#ifdef CONFIG_SERIAL_SHARE_IRQ
+               rs_interrupt(0, NULL, NULL);
+#else
+               rs_interrupt_single(0, NULL, NULL);
+#endif
+               restore_flags(flags);
+
+               mod_timer(&serial_timer, jiffies + IRQ_timeout[0]);
+       }
+}
+
+/*
+ * ---------------------------------------------------------------
+ * Low level utility subroutines for the serial driver:  routines to
+ * figure out the appropriate timeout for an interrupt chain, routines
+ * to initialize and startup a serial port, and routines to shutdown a
+ * serial port.  Useful stuff like that.
+ * ---------------------------------------------------------------
+ */
+
+/*
+ * This routine figures out the correct timeout for a particular IRQ.
+ * It uses the smallest timeout of all of the serial ports in a
+ * particular interrupt chain.  Now only used for IRQ 0....
+ */
+static void figure_IRQ_timeout(int irq)
+{
+       struct  async_struct    *info;
+       int     timeout = 60*HZ;        /* 60 seconds === a long time :-) */
+
+       info = IRQ_ports[irq];
+       if (!info) {
+               IRQ_timeout[irq] = 60*HZ;
+               return;
+       }
+       while (info) {
+               if (info->timeout < timeout)
+                       timeout = info->timeout;
+               info = info->next_port;
+       }
+       if (!irq)
+               timeout = timeout / 2;
+       IRQ_timeout[irq] = (timeout > 3) ? timeout-2 : 1;
+}
+
+#ifdef CONFIG_SERIAL_RSA
+/* Attempts to turn on the RSA FIFO.  Returns zero on failure */
+static int enable_rsa(struct async_struct *info)
+{
+       unsigned char mode;
+       int result;
+       unsigned long flags;
+
+       save_flags(flags); cli();
+       mode = serial_inp(info, UART_RSA_MSR);
+       result = mode & UART_RSA_MSR_FIFO;
+
+       if (!result) {
+               serial_outp(info, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO);
+               mode = serial_inp(info, UART_RSA_MSR);
+               result = mode & UART_RSA_MSR_FIFO;
+       }
+
+       restore_flags(flags);
+       return result;
+}
+
+/* Attempts to turn off the RSA FIFO.  Returns zero on failure */
+static int disable_rsa(struct async_struct *info)
+{
+       unsigned char mode;
+       int result;
+       unsigned long flags;
+
+       save_flags(flags); cli();
+       mode = serial_inp(info, UART_RSA_MSR);
+       result = !(mode & UART_RSA_MSR_FIFO);
+
+       if (!result) {
+               serial_outp(info, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO);
+               mode = serial_inp(info, UART_RSA_MSR);
+               result = !(mode & UART_RSA_MSR_FIFO);
+       }
+
+       restore_flags(flags);
+       return result;
+}
+#endif /* CONFIG_SERIAL_RSA */
+
+static int startup(struct async_struct * info)
+{
+       unsigned long flags;
+       int     retval=0;
+       void (*handler)(int, void *, struct pt_regs *);
+       struct serial_state *state= info->state;
+       unsigned long page;
+#ifdef CONFIG_SERIAL_MANY_PORTS
+       unsigned short ICP;
+#endif
+
+       page = get_zeroed_page(GFP_KERNEL);
+       if (!page)
+               return -ENOMEM;
+
+       save_flags(flags); cli();
+
+       if (info->flags & ASYNC_INITIALIZED) {
+               free_page(page);
+               goto errout;
+       }
+
+       if (!CONFIGURED_SERIAL_PORT(state) || !state->type) {
+               if (info->tty)
+                       set_bit(TTY_IO_ERROR, &info->tty->flags);
+               free_page(page);
+               goto errout;
+       }
+       if (info->xmit.buf)
+               free_page(page);
+       else
+               info->xmit.buf = (unsigned char *) page;
+
+#ifdef SERIAL_DEBUG_OPEN
+       printk("starting up ttys%d (irq %d)...", info->line, state->irq);
+#endif
+
+       if (uart_config[state->type].flags & UART_STARTECH) {
+               /* Wake up UART */
+               serial_outp(info, UART_LCR, 0xBF);
+               serial_outp(info, UART_EFR, UART_EFR_ECB);
+               /*
+                * Turn off LCR == 0xBF so we actually set the IER
+                * register on the XR16C850
+                */
+               serial_outp(info, UART_LCR, 0);
+               serial_outp(info, UART_IER, 0);
+               /*
+                * Now reset LCR so we can turn off the ECB bit
+                */
+               serial_outp(info, UART_LCR, 0xBF);
+               serial_outp(info, UART_EFR, 0);
+               /*
+                * For a XR16C850, we need to set the trigger levels
+                */
+               if (state->type == PORT_16850) {
+                       serial_outp(info, UART_FCTR, UART_FCTR_TRGD |
+                                       UART_FCTR_RX);
+                       serial_outp(info, UART_TRG, UART_TRG_96);
+                       serial_outp(info, UART_FCTR, UART_FCTR_TRGD |
+                                       UART_FCTR_TX);
+                       serial_outp(info, UART_TRG, UART_TRG_96);
+               }
+               serial_outp(info, UART_LCR, 0);
+       }
+
+       if (state->type == PORT_16750) {
+               /* Wake up UART */
+               serial_outp(info, UART_IER, 0);
+       }
+
+       if (state->type == PORT_16C950) {
+               /* Wake up and initialize UART */
+               info->ACR = 0;
+               serial_outp(info, UART_LCR, 0xBF);
+               serial_outp(info, UART_EFR, UART_EFR_ECB);
+               serial_outp(info, UART_IER, 0);
+               serial_outp(info, UART_LCR, 0);
+               serial_icr_write(info, UART_CSR, 0); /* Reset the UART */
+               serial_outp(info, UART_LCR, 0xBF);
+               serial_outp(info, UART_EFR, UART_EFR_ECB);
+               serial_outp(info, UART_LCR, 0);
+       }
+
+#ifdef CONFIG_SERIAL_RSA
+       /*
+        * If this is an RSA port, see if we can kick it up to the
+        * higher speed clock.
+        */
+       if (state->type == PORT_RSA) {
+               if (state->baud_base != SERIAL_RSA_BAUD_BASE &&
+                   enable_rsa(info))
+                       state->baud_base = SERIAL_RSA_BAUD_BASE;
+               if (state->baud_base == SERIAL_RSA_BAUD_BASE)
+                       serial_outp(info, UART_RSA_FRR, 0);
+       }
+#endif
+
+       /*
+        * Clear the FIFO buffers and disable them
+        * (they will be reenabled in change_speed())
+        */
+       if (uart_config[state->type].flags & UART_CLEAR_FIFO) {
+               serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
+               serial_outp(info, UART_FCR, (UART_FCR_ENABLE_FIFO |
+                                            UART_FCR_CLEAR_RCVR |
+                                            UART_FCR_CLEAR_XMIT));
+               serial_outp(info, UART_FCR, 0);
+       }
+
+       /*
+        * Clear the interrupt registers.
+        */
+       (void) serial_inp(info, UART_LSR);
+       (void) serial_inp(info, UART_RX);
+       (void) serial_inp(info, UART_IIR);
+       (void) serial_inp(info, UART_MSR);
+
+       /*
+        * 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 (!(info->flags & ASYNC_BUGGY_UART) &&
+           (serial_inp(info, UART_LSR) == 0xff)) {
+               printk("ttyS%d: LSR safety check engaged!\n", state->line);
+               if (capable(CAP_SYS_ADMIN)) {
+                       if (info->tty)
+                               set_bit(TTY_IO_ERROR, &info->tty->flags);
+               } else
+                       retval = -ENODEV;
+               goto errout;
+       }
+       
+       /*
+        * Allocate the IRQ if necessary
+        */
+       if (state->irq && (!IRQ_ports[state->irq] ||
+                         !IRQ_ports[state->irq]->next_port)) {
+               if (IRQ_ports[state->irq]) {
+#ifdef CONFIG_SERIAL_SHARE_IRQ
+                       free_irq(state->irq, &IRQ_ports[state->irq]);
+#ifdef CONFIG_SERIAL_MULTIPORT                         
+                       if (rs_multiport[state->irq].port1)
+                               handler = rs_interrupt_multi;
+                       else
+#endif
+                               handler = rs_interrupt;
+#else
+                       retval = -EBUSY;
+                       goto errout;
+#endif /* CONFIG_SERIAL_SHARE_IRQ */
+               } else 
+                       handler = rs_interrupt_single;
+
+               retval = request_irq(state->irq, handler, SA_SHIRQ,
+                                    "serial", &IRQ_ports[state->irq]);
+               if (retval) {
+                       if (capable(CAP_SYS_ADMIN)) {
+                               if (info->tty)
+                                       set_bit(TTY_IO_ERROR,
+                                               &info->tty->flags);
+                               retval = 0;
+                       }
+                       goto errout;
+               }
+       }
+
+       /*
+        * Insert serial port into IRQ chain.
+        */
+       info->prev_port = 0;
+       info->next_port = IRQ_ports[state->irq];
+       if (info->next_port)
+               info->next_port->prev_port = info;
+       IRQ_ports[state->irq] = info;
+       figure_IRQ_timeout(state->irq);
+
+       /*
+        * Now, initialize the UART 
+        */
+       serial_outp(info, UART_LCR, UART_LCR_WLEN8);    /* reset DLAB */
+
+       info->MCR = 0;
+       if (info->tty->termios->c_cflag & CBAUD)
+               info->MCR = UART_MCR_DTR | UART_MCR_RTS;
+#ifdef CONFIG_SERIAL_MANY_PORTS
+       if (info->flags & ASYNC_FOURPORT) {
+               if (state->irq == 0)
+                       info->MCR |= UART_MCR_OUT1;
+       } else
+#endif
+       {
+               if (state->irq != 0)
+                       info->MCR |= UART_MCR_OUT2;
+       }
+       info->MCR |= ALPHA_KLUDGE_MCR;          /* Don't ask */
+       serial_outp(info, UART_MCR, info->MCR);
+       
+       /*
+        * Finally, enable interrupts
+        */
+       info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
+       serial_outp(info, UART_IER, info->IER); /* enable interrupts */
+       
+#ifdef CONFIG_SERIAL_MANY_PORTS
+       if (info->flags & ASYNC_FOURPORT) {
+               /* Enable interrupts on the AST Fourport board */
+               ICP = (info->port & 0xFE0) | 0x01F;
+               outb_p(0x80, ICP);
+               (void) inb_p(ICP);
+       }
+#endif
+
+       /*
+        * And clear the interrupt registers again for luck.
+        */
+       (void)serial_inp(info, UART_LSR);
+       (void)serial_inp(info, UART_RX);
+       (void)serial_inp(info, UART_IIR);
+       (void)serial_inp(info, UART_MSR);
+
+       if (info->tty)
+               clear_bit(TTY_IO_ERROR, &info->tty->flags);
+       info->xmit.head = info->xmit.tail = 0;
+
+       /*
+        * Set up serial timers...
+        */
+       mod_timer(&serial_timer, jiffies + 2*HZ/100);
+
+       /*
+        * Set up the tty->alt_speed kludge
+        */
+#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
+       if (info->tty) {
+               if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+                       info->tty->alt_speed = 57600;
+               if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+                       info->tty->alt_speed = 115200;
+               if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+                       info->tty->alt_speed = 230400;
+               if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+                       info->tty->alt_speed = 460800;
+       }
+#endif
+       
+       /*
+        * and set the speed of the serial port
+        */
+       change_speed(info, 0);
+
+       info->flags |= ASYNC_INITIALIZED;
+       restore_flags(flags);
+       return 0;
+       
+errout:
+       restore_flags(flags);
+       return retval;
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ */
+static void shutdown(struct async_struct * info)
+{
+       unsigned long   flags;
+       struct serial_state *state;
+       int             retval;
+
+       if (!(info->flags & ASYNC_INITIALIZED))
+               return;
+
+       state = info->state;
+
+#ifdef SERIAL_DEBUG_OPEN
+       printk("Shutting down serial port %d (irq %d)....", info->line,
+              state->irq);
+#endif
+       
+       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);
+       
+       /*
+        * First unlink the serial port from the IRQ chain...
+        */
+       if (info->next_port)
+               info->next_port->prev_port = info->prev_port;
+       if (info->prev_port)
+               info->prev_port->next_port = info->next_port;
+       else
+               IRQ_ports[state->irq] = info->next_port;
+       figure_IRQ_timeout(state->irq);
+       
+       /*
+        * Free the IRQ, if necessary
+        */
+       if (state->irq && (!IRQ_ports[state->irq] ||
+                         !IRQ_ports[state->irq]->next_port)) {
+               if (IRQ_ports[state->irq]) {
+                       free_irq(state->irq, &IRQ_ports[state->irq]);
+                       retval = request_irq(state->irq, rs_interrupt_single,
+                                            SA_SHIRQ, "serial",
+                                            &IRQ_ports[state->irq]);
+                       
+                       if (retval)
+                               printk("serial shutdown: request_irq: error %d"
+                                      "  Couldn't reacquire IRQ.\n", retval);
+               } else
+                       free_irq(state->irq, &IRQ_ports[state->irq]);
+       }
+
+       if (info->xmit.buf) {
+               unsigned long pg = (unsigned long) info->xmit.buf;
+               info->xmit.buf = 0;
+               free_page(pg);
+       }
+
+       info->IER = 0;
+       serial_outp(info, UART_IER, 0x00);      /* disable all intrs */
+#ifdef CONFIG_SERIAL_MANY_PORTS
+       if (info->flags & ASYNC_FOURPORT) {
+               /* reset interrupts on the AST Fourport board */
+               (void) inb((info->port & 0xFE0) | 0x01F);
+               info->MCR |= UART_MCR_OUT1;
+       } else
+#endif
+               info->MCR &= ~UART_MCR_OUT2;
+       info->MCR |= ALPHA_KLUDGE_MCR;          /* Don't ask */
+       
+       /* disable break condition */
+       serial_out(info, UART_LCR, serial_inp(info, UART_LCR) & ~UART_LCR_SBC);
+       
+       if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
+               info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
+       serial_outp(info, UART_MCR, info->MCR);
+
+       /* disable FIFO's */    
+       serial_outp(info, UART_FCR, (UART_FCR_ENABLE_FIFO |
+                                    UART_FCR_CLEAR_RCVR |
+                                    UART_FCR_CLEAR_XMIT));
+       serial_outp(info, UART_FCR, 0);
+
+#ifdef CONFIG_SERIAL_RSA
+       /*
+        * Reset the RSA board back to 115kbps compat mode.
+        */
+       if ((state->type == PORT_RSA) &&
+           (state->baud_base == SERIAL_RSA_BAUD_BASE &&
+            disable_rsa(info)))
+               state->baud_base = SERIAL_RSA_BAUD_BASE_LO;
+#endif
+       
+
+       (void)serial_in(info, UART_RX);    /* read data port to reset things */
+       
+       if (info->tty)
+               set_bit(TTY_IO_ERROR, &info->tty->flags);
+
+       if (uart_config[info->state->type].flags & UART_STARTECH) {
+               /* Arrange to enter sleep mode */
+               serial_outp(info, UART_LCR, 0xBF);
+               serial_outp(info, UART_EFR, UART_EFR_ECB);
+               serial_outp(info, UART_LCR, 0);
+               serial_outp(info, UART_IER, UART_IERX_SLEEP);
+               serial_outp(info, UART_LCR, 0xBF);
+               serial_outp(info, UART_EFR, 0);
+               serial_outp(info, UART_LCR, 0);
+       }
+       if (info->state->type == PORT_16750) {
+               /* Arrange to enter sleep mode */
+               serial_outp(info, UART_IER, UART_IERX_SLEEP);
+       }
+       info->flags &= ~ASYNC_INITIALIZED;
+       restore_flags(flags);
+}
+
+#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
+static int baud_table[] = {
+       0, 50, 75, 110, 134, 150, 200, 300,
+       600, 1200, 1800, 2400, 4800, 9600, 19200,
+       38400, 57600, 115200, 230400, 460800, 0 };
+
+static int tty_get_baud_rate(struct tty_struct *tty)
+{
+       struct async_struct * info = (struct async_struct *)tty->driver_data;
+       unsigned int cflag, i;
+
+       cflag = tty->termios->c_cflag;
+
+       i = cflag & CBAUD;
+       if (i & CBAUDEX) {
+               i &= ~CBAUDEX;
+               if (i < 1 || i > 2) 
+                       tty->termios->c_cflag &= ~CBAUDEX;
+               else
+                       i += 15;
+       }
+       if (i == 15) {
+               if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+                       i += 1;
+               if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+                       i += 2;
+       }
+       return baud_table[i];
+}
+#endif
+
+/*
+ * This routine is called to set the UART divisor registers to match
+ * the specified baud rate for a serial port.
+ */
+static void change_speed(struct async_struct *info,
+                        struct termios *old_termios)
+{
+       int     quot = 0, baud_base, baud;
+       unsigned cflag, cval, fcr = 0;
+       int     bits;
+       unsigned long   flags;
+
+       if (!info->tty || !info->tty->termios)
+               return;
+       cflag = info->tty->termios->c_cflag;
+       if (!CONFIGURED_SERIAL_PORT(info))
+               return;
+
+       /* byte size and parity */
+       switch (cflag & CSIZE) {
+             case CS5: cval = 0x00; bits = 7; break;
+             case CS6: cval = 0x01; bits = 8; break;
+             case CS7: cval = 0x02; bits = 9; break;
+             case CS8: cval = 0x03; bits = 10; break;
+             /* Never happens, but GCC is too dumb to figure it out */
+             default:  cval = 0x00; bits = 7; break;
+             }
+       if (cflag & CSTOPB) {
+               cval |= 0x04;
+               bits++;
+       }
+       if (cflag & PARENB) {
+               cval |= UART_LCR_PARITY;
+               bits++;
+       }
+       if (!(cflag & PARODD))
+               cval |= UART_LCR_EPAR;
+#ifdef CMSPAR
+       if (cflag & CMSPAR)
+               cval |= UART_LCR_SPAR;
+#endif
+
+       /* Determine divisor based on baud rate */
+       baud = tty_get_baud_rate(info->tty);
+       if (!baud)
+               baud = 9600;    /* B0 transition handled in rs_set_termios */
+#ifdef CONFIG_SERIAL_RSA
+       if ((info->state->type == PORT_RSA) &&
+           (info->state->baud_base != SERIAL_RSA_BAUD_BASE) &&
+           enable_rsa(info))
+               info->state->baud_base = SERIAL_RSA_BAUD_BASE;
+#endif
+       baud_base = info->state->baud_base;
+       if (info->state->type == PORT_16C950) {
+               if (baud <= baud_base)
+                       serial_icr_write(info, UART_TCR, 0);
+               else if (baud <= 2*baud_base) {
+                       serial_icr_write(info, UART_TCR, 0x8);
+                       baud_base = baud_base * 2;
+               } else if (baud <= 4*baud_base) {
+                       serial_icr_write(info, UART_TCR, 0x4);
+                       baud_base = baud_base * 4;
+               } else
+                       serial_icr_write(info, UART_TCR, 0);
+       }
+       if (baud == 38400 &&
+           ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))
+               quot = info->state->custom_divisor;
+       else {
+               if (baud == 134)
+                       /* Special case since 134 is really 134.5 */
+                       quot = (2*baud_base / 269);
+               else if (baud)
+                       quot = baud_base / baud;
+       }
+       /* If the quotient is zero refuse the change */
+       if (!quot && old_termios) {
+               info->tty->termios->c_cflag &= ~CBAUD;
+               info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD);
+               baud = tty_get_baud_rate(info->tty);
+               if (!baud)
+                       baud = 9600;
+               if (baud == 38400 &&
+                   ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))
+                       quot = info->state->custom_divisor;
+               else {
+                       if (baud == 134)
+                               /* Special case since 134 is really 134.5 */
+                               quot = (2*baud_base / 269);
+                       else if (baud)
+                               quot = baud_base / baud;
+               }
+       }
+       /* As a last resort, if the quotient is zero, default to 9600 bps */
+       if (!quot)
+               quot = baud_base / 9600;
+       /*
+        * Work around a bug in the Oxford Semiconductor 952 rev B
+        * chip which causes it to seriously miscalculate baud rates
+        * when DLL is 0.
+        */
+       if (((quot & 0xFF) == 0) && (info->state->type == PORT_16C950) &&
+           (info->state->revision == 0x5201))
+               quot++;
+       
+       info->quot = quot;
+       info->timeout = ((info->xmit_fifo_size*HZ*bits*quot) / baud_base);
+       info->timeout += HZ/50;         /* Add .02 seconds of slop */
+
+       /* Set up FIFO's */
+       if (uart_config[info->state->type].flags & UART_USE_FIFO) {
+               if ((info->state->baud_base / quot) < 2400)
+                       fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
+#ifdef CONFIG_SERIAL_RSA
+               else if (info->state->type == PORT_RSA)
+                       fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_14;
+#endif
+               else
+                       fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8;
+       }
+       if (info->state->type == PORT_16750)
+               fcr |= UART_FCR7_64BYTE;
+       
+       /* CTS flow control flag and modem status interrupts */
+       info->IER &= ~UART_IER_MSI;
+       if (info->flags & ASYNC_HARDPPS_CD)
+               info->IER |= UART_IER_MSI;
+       if (cflag & CRTSCTS) {
+               info->flags |= ASYNC_CTS_FLOW;
+               info->IER |= UART_IER_MSI;
+       } else
+               info->flags &= ~ASYNC_CTS_FLOW;
+       if (cflag & CLOCAL)
+               info->flags &= ~ASYNC_CHECK_CD;
+       else {
+               info->flags |= ASYNC_CHECK_CD;
+               info->IER |= UART_IER_MSI;
+       }
+       serial_out(info, UART_IER, info->IER);
+
+       /*
+        * Set up parity check flag
+        */
+#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+
+       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;
+       
+       /*
+        * Characters to ignore
+        */
+       info->ignore_status_mask = 0;
+       if (I_IGNPAR(info->tty))
+               info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
+       if (I_IGNBRK(info->tty)) {
+               info->ignore_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;
+       }
+       /*
+        * !!! ignore all characters if CREAD is not set
+        */
+       if ((cflag & CREAD) == 0)
+               info->ignore_status_mask |= UART_LSR_DR;
+       save_flags(flags); cli();
+       if (uart_config[info->state->type].flags & UART_STARTECH) {
+               serial_outp(info, UART_LCR, 0xBF);
+               serial_outp(info, UART_EFR,
+                           (cflag & CRTSCTS) ? UART_EFR_CTS : 0);
+       }
+       serial_outp(info, UART_LCR, cval | UART_LCR_DLAB);      /* set DLAB */
+       serial_outp(info, UART_DLL, quot & 0xff);       /* LS of divisor */
+       serial_outp(info, UART_DLM, quot >> 8);         /* MS of divisor */
+       if (info->state->type == PORT_16750)
+               serial_outp(info, UART_FCR, fcr);       /* set fcr */
+       serial_outp(info, UART_LCR, cval);              /* reset DLAB */
+       info->LCR = cval;                               /* Save LCR */
+       if (info->state->type != PORT_16750) {
+               if (fcr & UART_FCR_ENABLE_FIFO) {
+                       /* emulated UARTs (Lucent Venus 167x) need two steps */
+                       serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
+               }
+               serial_outp(info, UART_FCR, fcr);       /* set fcr */
+       }
+       restore_flags(flags);
+}
+
+static void rs_put_char(struct tty_struct *tty, unsigned char ch)
+{
+       struct async_struct *info = (struct async_struct *)tty->driver_data;
+       unsigned long flags;
+
+       if (serial_paranoia_check(info, tty->device, "rs_put_char"))
+               return;
+
+       if (!tty || !info->xmit.buf)
+               return;
+
+       save_flags(flags); cli();
+       if (CIRC_SPACE(info->xmit.head,
+                      info->xmit.tail,
+                      SERIAL_XMIT_SIZE) == 0) {
+               restore_flags(flags);
+               return;
+       }
+
+       info->xmit.buf[info->xmit.head] = ch;
+       info->xmit.head = (info->xmit.head + 1) & (SERIAL_XMIT_SIZE-1);
+       restore_flags(flags);
+}
+
+static void rs_flush_chars(struct tty_struct *tty)
+{
+       struct async_struct *info = (struct async_struct *)tty->driver_data;
+       unsigned long flags;
+                               
+       if (serial_paranoia_check(info, tty->device, "rs_flush_chars"))
+               return;
+
+       if (info->xmit.head == info->xmit.tail
+           || tty->stopped
+           || tty->hw_stopped
+           || !info->xmit.buf)
+               return;
+
+       save_flags(flags); cli();
+       info->IER |= UART_IER_THRI;
+       serial_out(info, UART_IER, info->IER);
+       restore_flags(flags);
+}
+
+static int rs_write(struct tty_struct * tty, int from_user,
+                   const unsigned char *buf, int count)
+{
+       int     c, ret = 0;
+       struct async_struct *info = (struct async_struct *)tty->driver_data;
+       unsigned long flags;
+                               
+       if (serial_paranoia_check(info, tty->device, "rs_write"))
+               return 0;
+
+       if (!tty || !info->xmit.buf || !tmp_buf)
+               return 0;
+
+       save_flags(flags);
+       if (from_user) {
+               down(&tmp_buf_sem);
+               while (1) {
+                       int c1;
+                       c = CIRC_SPACE_TO_END(info->xmit.head,
+                                             info->xmit.tail,
+                                             SERIAL_XMIT_SIZE);
+                       if (count < c)
+                               c = count;
+                       if (c <= 0)
+                               break;
+
+                       c -= copy_from_user(tmp_buf, buf, c);
+                       if (!c) {
+                               if (!ret)
+                                       ret = -EFAULT;
+                               break;
+                       }
+                       cli();
+                       c1 = CIRC_SPACE_TO_END(info->xmit.head,
+                                              info->xmit.tail,
+                                              SERIAL_XMIT_SIZE);
+                       if (c1 < c)
+                               c = c1;
+                       memcpy(info->xmit.buf + info->xmit.head, tmp_buf, c);
+                       info->xmit.head = ((info->xmit.head + c) &
+                                          (SERIAL_XMIT_SIZE-1));
+                       restore_flags(flags);
+                       buf += c;
+                       count -= c;
+                       ret += c;
+               }
+               up(&tmp_buf_sem);
+       } else {
+               cli();
+               while (1) {
+                       c = CIRC_SPACE_TO_END(info->xmit.head,
+                                             info->xmit.tail,
+                                             SERIAL_XMIT_SIZE);
+                       if (count < c)
+                               c = count;
+                       if (c <= 0) {
+                               break;
+                       }
+                       memcpy(info->xmit.buf + info->xmit.head, buf, c);
+                       info->xmit.head = ((info->xmit.head + c) &
+                                          (SERIAL_XMIT_SIZE-1));
+                       buf += c;
+                       count -= c;
+                       ret += c;
+               }
+               restore_flags(flags);
+       }
+       if (info->xmit.head != info->xmit.tail
+           && !tty->stopped
+           && !tty->hw_stopped
+           && !(info->IER & UART_IER_THRI)) {
+               info->IER |= UART_IER_THRI;
+               serial_out(info, UART_IER, info->IER);
+       }
+       return ret;
+}
+
+static int rs_write_room(struct tty_struct *tty)
+{
+       struct async_struct *info = (struct async_struct *)tty->driver_data;
+
+       if (serial_paranoia_check(info, tty->device, "rs_write_room"))
+               return 0;
+       return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
+}
+
+static int rs_chars_in_buffer(struct tty_struct *tty)
+{
+       struct async_struct *info = (struct async_struct *)tty->driver_data;
+                               
+       if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer"))
+               return 0;
+       return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
+}
+
+static void rs_flush_buffer(struct tty_struct *tty)
+{
+       struct async_struct *info = (struct async_struct *)tty->driver_data;
+       unsigned long flags;
+       
+       if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))
+               return;
+       save_flags(flags); cli();
+       info->xmit.head = info->xmit.tail = 0;
+       restore_flags(flags);
+#ifdef SERIAL_HAVE_POLL_WAIT
+       wake_up_interruptible(&tty->poll_wait);
+#endif
+       tty_wakeup(tty);
+}
+
+/*
+ * This function is used to send a high-priority XON/XOFF character to
+ * the device
+ */
+static void rs_send_xchar(struct tty_struct *tty, char ch)
+{
+       struct async_struct *info = (struct async_struct *)tty->driver_data;
+
+       if (serial_paranoia_check(info, tty->device, "rs_send_char"))
+               return;
+
+       info->x_char = ch;
+       if (ch) {
+               /* Make sure transmit interrupts are on */
+               info->IER |= UART_IER_THRI;
+               serial_out(info, UART_IER, info->IER);
+       }
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_throttle()
+ * 
+ * This routine is called by the upper-layer tty layer to signal that
+ * incoming characters should be throttled.
+ * ------------------------------------------------------------
+ */
+static void rs_throttle(struct tty_struct * tty)
+{
+       struct async_struct *info = (struct async_struct *)tty->driver_data;
+       unsigned long flags;
+#ifdef SERIAL_DEBUG_THROTTLE
+       char    buf[64];
+       
+       printk("throttle %s: %d....\n", tty_name(tty, buf),
+              tty->ldisc.chars_in_buffer(tty));
+#endif
+
+       if (serial_paranoia_check(info, tty->device, "rs_throttle"))
+               return;
+       
+       if (I_IXOFF(tty))
+               rs_send_xchar(tty, STOP_CHAR(tty));
+
+       if (tty->termios->c_cflag & CRTSCTS)
+               info->MCR &= ~UART_MCR_RTS;
+
+       save_flags(flags); cli();
+       serial_out(info, UART_MCR, info->MCR);
+       restore_flags(flags);
+}
+
+static void rs_unthrottle(struct tty_struct * tty)
+{
+       struct async_struct *info = (struct async_struct *)tty->driver_data;
+       unsigned long flags;
+#ifdef SERIAL_DEBUG_THROTTLE
+       char    buf[64];
+       
+       printk("unthrottle %s: %d....\n", tty_name(tty, buf),
+              tty->ldisc.chars_in_buffer(tty));
+#endif
+
+       if (serial_paranoia_check(info, tty->device, "rs_unthrottle"))
+               return;
+       
+       if (I_IXOFF(tty)) {
+               if (info->x_char)
+                       info->x_char = 0;
+               else
+                       rs_send_xchar(tty, START_CHAR(tty));
+       }
+       if (tty->termios->c_cflag & CRTSCTS)
+               info->MCR |= UART_MCR_RTS;
+       save_flags(flags); cli();
+       serial_out(info, UART_MCR, info->MCR);
+       restore_flags(flags);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_ioctl() and friends
+ * ------------------------------------------------------------
+ */
+
+static int get_serial_info(struct async_struct * info,
+                          struct serial_struct * retinfo)
+{
+       struct serial_struct tmp;
+       struct serial_state *state = info->state;
+   
+       if (!retinfo)
+               return -EFAULT;
+       memset(&tmp, 0, sizeof(tmp));
+       tmp.type = state->type;
+       tmp.line = state->line;
+       tmp.port = state->port;
+       if (HIGH_BITS_OFFSET)
+               tmp.port_high = state->port >> HIGH_BITS_OFFSET;
+       else
+               tmp.port_high = 0;
+       tmp.irq = state->irq;
+       tmp.flags = state->flags;
+       tmp.xmit_fifo_size = state->xmit_fifo_size;
+       tmp.baud_base = state->baud_base;
+       tmp.close_delay = state->close_delay;
+       tmp.closing_wait = state->closing_wait;
+       tmp.custom_divisor = state->custom_divisor;
+       tmp.hub6 = state->hub6;
+       tmp.io_type = state->io_type;
+       if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
+               return -EFAULT;
+       return 0;
+}
+
+static int set_serial_info(struct async_struct * info,
+                          struct serial_struct * new_info)
+{
+       struct serial_struct new_serial;
+       struct serial_state old_state, *state;
+       unsigned int            i,change_irq,change_port;
+       int                     retval = 0;
+       unsigned long           new_port;
+
+       if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
+               return -EFAULT;
+       state = info->state;
+       old_state = *state;
+
+       new_port = new_serial.port;
+       if (HIGH_BITS_OFFSET)
+               new_port += (unsigned long) new_serial.port_high << 
HIGH_BITS_OFFSET;
+
+       change_irq = new_serial.irq != state->irq;
+       change_port = (new_port != ((int) state->port)) ||
+               (new_serial.hub6 != state->hub6);
+  
+       if (!capable(CAP_SYS_ADMIN)) {
+               if (change_irq || change_port ||
+                   (new_serial.baud_base != state->baud_base) ||
+                   (new_serial.type != state->type) ||
+                   (new_serial.close_delay != state->close_delay) ||
+                   (new_serial.xmit_fifo_size != state->xmit_fifo_size) ||
+                   ((new_serial.flags & ~ASYNC_USR_MASK) !=
+                    (state->flags & ~ASYNC_USR_MASK)))
+                       return -EPERM;
+               state->flags = ((state->flags & ~ASYNC_USR_MASK) |
+                              (new_serial.flags & ASYNC_USR_MASK));
+               info->flags = ((info->flags & ~ASYNC_USR_MASK) |
+                              (new_serial.flags & ASYNC_USR_MASK));
+               state->custom_divisor = new_serial.custom_divisor;
+               goto check_and_exit;
+       }
+
+       new_serial.irq = irq_cannonicalize(new_serial.irq);
+
+       if ((new_serial.irq >= NR_IRQS) || (new_serial.irq < 0) || 
+           (new_serial.baud_base < 9600)|| (new_serial.type < PORT_UNKNOWN) ||
+           (new_serial.type > PORT_MAX) || (new_serial.type == PORT_CIRRUS) ||
+           (new_serial.type == PORT_STARTECH)) {
+               return -EINVAL;
+       }
+
+       if ((new_serial.type != state->type) ||
+           (new_serial.xmit_fifo_size <= 0))
+               new_serial.xmit_fifo_size =
+                       uart_config[new_serial.type].dfl_xmit_fifo_size;
+
+       /* Make sure address is not already in use */
+       if (new_serial.type) {
+               for (i = 0 ; i < NR_PORTS; i++)
+                       if ((state != &rs_table[i]) &&
+                           (rs_table[i].io_type == SERIAL_IO_PORT) &&
+                           (rs_table[i].port == new_port) &&
+                           rs_table[i].type)
+                               return -EADDRINUSE;
+       }
+
+       if ((change_port || change_irq) && (state->count > 1))
+               return -EBUSY;
+
+       /*
+        * OK, past this point, all the error checking has been done.
+        * At this point, we start making changes.....
+        */
+
+       state->baud_base = new_serial.baud_base;
+       state->flags = ((state->flags & ~ASYNC_FLAGS) |
+                       (new_serial.flags & ASYNC_FLAGS));
+       info->flags = ((state->flags & ~ASYNC_INTERNAL_FLAGS) |
+                      (info->flags & ASYNC_INTERNAL_FLAGS));
+       state->custom_divisor = new_serial.custom_divisor;
+       state->close_delay = new_serial.close_delay * HZ/100;
+       state->closing_wait = new_serial.closing_wait * HZ/100;
+#if (LINUX_VERSION_CODE > 0x20100)
+       info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+#endif
+       info->xmit_fifo_size = state->xmit_fifo_size =
+               new_serial.xmit_fifo_size;
+
+       if ((state->type != PORT_UNKNOWN) && state->port) {
+#ifdef CONFIG_SERIAL_RSA
+               if (old_state.type == PORT_RSA)
+                       release_region(state->port + UART_RSA_BASE, 16);
+               else
+#endif
+               release_region(state->port,8);
+       }
+       state->type = new_serial.type;
+       if (change_port || change_irq) {
+               /*
+                * We need to shutdown the serial port at the old
+                * port/irq combination.
+                */
+               shutdown(info);
+               state->irq = new_serial.irq;
+               info->port = state->port = new_port;
+               info->hub6 = state->hub6 = new_serial.hub6;
+               if (info->hub6)
+                       info->io_type = state->io_type = SERIAL_IO_HUB6;
+               else if (info->io_type == SERIAL_IO_HUB6)
+                       info->io_type = state->io_type = SERIAL_IO_PORT;
+       }
+       if ((state->type != PORT_UNKNOWN) && state->port) {
+#ifdef CONFIG_SERIAL_RSA
+               if (state->type == PORT_RSA)
+                       request_region(state->port + UART_RSA_BASE,
+                                      16, "serial_rsa(set)");
+               else
+#endif
+                       request_region(state->port,8,"serial(set)");
+       }
+
+       
+check_and_exit:
+       if ((!state->port && !state->iomem_base) || !state->type)
+               return 0;
+       if (info->flags & ASYNC_INITIALIZED) {
+               if (((old_state.flags & ASYNC_SPD_MASK) !=
+                    (state->flags & ASYNC_SPD_MASK)) ||
+                   (old_state.custom_divisor != state->custom_divisor)) {
+#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
+                       if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+                               info->tty->alt_speed = 57600;
+                       if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+                               info->tty->alt_speed = 115200;
+                       if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+                               info->tty->alt_speed = 230400;
+                       if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+                               info->tty->alt_speed = 460800;
+#endif
+                       change_speed(info, 0);
+               }
+       } else
+               retval = startup(info);
+       return retval;
+}
+
+
+/*
+ * get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ *         is emptied.  On bus types like RS485, the transmitter must
+ *         release the bus after transmitting. This must be done when
+ *         the transmit shift register is empty, not be done when the
+ *         transmit holding register is empty.  This functionality
+ *         allows an RS485 driver to be written in user space. 
+ */
+static int get_lsr_info(struct async_struct * info, unsigned int *value)
+{
+       unsigned char status;
+       unsigned int result;
+       unsigned long flags;
+
+       save_flags(flags); cli();
+       status = serial_in(info, UART_LSR);
+       restore_flags(flags);
+       result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
+
+       /*
+        * If we're about to load something into the transmit
+        * register, we'll pretend the transmitter isn't empty to
+        * avoid a race condition (depending on when the transmit
+        * interrupt happens).
+        */
+       if (info->x_char || 
+           ((CIRC_CNT(info->xmit.head, info->xmit.tail,
+                      SERIAL_XMIT_SIZE) > 0) &&
+            !info->tty->stopped && !info->tty->hw_stopped))
+               result &= ~TIOCSER_TEMT;
+
+       if (copy_to_user(value, &result, sizeof(int)))
+               return -EFAULT;
+       return 0;
+}
+
+
+static int get_modem_info(struct async_struct * info, unsigned int *value)
+{
+       unsigned char control, status;
+       unsigned int result;
+       unsigned long flags;
+
+       control = info->MCR;
+       save_flags(flags); cli();
+       status = serial_in(info, UART_MSR);
+       restore_flags(flags);
+       result =  ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
+               | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
+#ifdef TIOCM_OUT1
+               | ((control & UART_MCR_OUT1) ? TIOCM_OUT1 : 0)
+               | ((control & UART_MCR_OUT2) ? TIOCM_OUT2 : 0)
+#endif
+               | ((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);
+
+       if (copy_to_user(value, &result, sizeof(int)))
+               return -EFAULT;
+       return 0;
+}
+
+static int set_modem_info(struct async_struct * info, unsigned int cmd,
+                         unsigned int *value)
+{
+       unsigned int arg;
+       unsigned long flags;
+
+       if (copy_from_user(&arg, value, sizeof(int)))
+               return -EFAULT;
+
+       switch (cmd) {
+       case TIOCMBIS: 
+               if (arg & TIOCM_RTS)
+                       info->MCR |= UART_MCR_RTS;
+               if (arg & TIOCM_DTR)
+                       info->MCR |= UART_MCR_DTR;
+#ifdef TIOCM_OUT1
+               if (arg & TIOCM_OUT1)
+                       info->MCR |= UART_MCR_OUT1;
+               if (arg & TIOCM_OUT2)
+                       info->MCR |= UART_MCR_OUT2;
+#endif
+               if (arg & TIOCM_LOOP)
+                       info->MCR |= UART_MCR_LOOP;
+               break;
+       case TIOCMBIC:
+               if (arg & TIOCM_RTS)
+                       info->MCR &= ~UART_MCR_RTS;
+               if (arg & TIOCM_DTR)
+                       info->MCR &= ~UART_MCR_DTR;
+#ifdef TIOCM_OUT1
+               if (arg & TIOCM_OUT1)
+                       info->MCR &= ~UART_MCR_OUT1;
+               if (arg & TIOCM_OUT2)
+                       info->MCR &= ~UART_MCR_OUT2;
+#endif
+               if (arg & TIOCM_LOOP)
+                       info->MCR &= ~UART_MCR_LOOP;
+               break;
+       case TIOCMSET:
+               info->MCR = ((info->MCR & ~(UART_MCR_RTS |
+#ifdef TIOCM_OUT1
+                                           UART_MCR_OUT1 |
+                                           UART_MCR_OUT2 |
+#endif
+                                           UART_MCR_LOOP |
+                                           UART_MCR_DTR))
+                            | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0)
+#ifdef TIOCM_OUT1
+                            | ((arg & TIOCM_OUT1) ? UART_MCR_OUT1 : 0)
+                            | ((arg & TIOCM_OUT2) ? UART_MCR_OUT2 : 0)
+#endif
+                            | ((arg & TIOCM_LOOP) ? UART_MCR_LOOP : 0)
+                            | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0));
+               break;
+       default:
+               return -EINVAL;
+       }
+       save_flags(flags); cli();
+       info->MCR |= ALPHA_KLUDGE_MCR;          /* Don't ask */
+       serial_out(info, UART_MCR, info->MCR);
+       restore_flags(flags);
+       return 0;
+}
+
+static int do_autoconfig(struct async_struct * info)
+{
+       int irq, retval;
+       
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       
+       if (info->state->count > 1)
+               return -EBUSY;
+       
+       shutdown(info);
+
+       autoconfig(info->state);
+       if ((info->state->flags & ASYNC_AUTO_IRQ) &&
+           (info->state->port != 0  || info->state->iomem_base != 0) &&
+           (info->state->type != PORT_UNKNOWN)) {
+               irq = detect_uart_irq(info->state);
+               if (irq > 0)
+                       info->state->irq = irq;
+       }
+
+       retval = startup(info);
+       if (retval)
+               return retval;
+       return 0;
+}
+
+/*
+ * rs_break() --- routine which turns the break handling on or off
+ */
+#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
+static void send_break(        struct async_struct * info, int duration)
+{
+       if (!CONFIGURED_SERIAL_PORT(info))
+               return;
+       current->state = TASK_INTERRUPTIBLE;
+       current->timeout = jiffies + duration;
+       cli();
+       info->LCR |= UART_LCR_SBC;
+       serial_out(info, UART_LCR, info->LCR);
+       schedule();
+       info->LCR &= ~UART_LCR_SBC;
+       serial_out(info, UART_LCR, info->LCR);
+       sti();
+}
+#else
+static void rs_break(struct tty_struct *tty, int break_state)
+{
+       struct async_struct * info = (struct async_struct *)tty->driver_data;
+       unsigned long flags;
+       
+       if (serial_paranoia_check(info, tty->device, "rs_break"))
+               return;
+
+       if (!CONFIGURED_SERIAL_PORT(info))
+               return;
+       save_flags(flags); cli();
+       if (break_state == -1)
+               info->LCR |= UART_LCR_SBC;
+       else
+               info->LCR &= ~UART_LCR_SBC;
+       serial_out(info, UART_LCR, info->LCR);
+       restore_flags(flags);
+}
+#endif
+
+#ifdef CONFIG_SERIAL_MULTIPORT
+static int get_multiport_struct(struct async_struct * info,
+                               struct serial_multiport_struct *retinfo)
+{
+       struct serial_multiport_struct ret;
+       struct rs_multiport_struct *multi;
+       
+       multi = &rs_multiport[info->state->irq];
+
+       ret.port_monitor = multi->port_monitor;
+       
+       ret.port1 = multi->port1;
+       ret.mask1 = multi->mask1;
+       ret.match1 = multi->match1;
+       
+       ret.port2 = multi->port2;
+       ret.mask2 = multi->mask2;
+       ret.match2 = multi->match2;
+       
+       ret.port3 = multi->port3;
+       ret.mask3 = multi->mask3;
+       ret.match3 = multi->match3;
+       
+       ret.port4 = multi->port4;
+       ret.mask4 = multi->mask4;
+       ret.match4 = multi->match4;
+
+       ret.irq = info->state->irq;
+
+       if (copy_to_user(retinfo,&ret,sizeof(*retinfo)))
+               return -EFAULT;
+       return 0;
+}
+
+static int set_multiport_struct(struct async_struct * info,
+                               struct serial_multiport_struct *in_multi)
+{
+       struct serial_multiport_struct new_multi;
+       struct rs_multiport_struct *multi;
+       struct serial_state *state;
+       int     was_multi, now_multi;
+       int     retval;
+       void (*handler)(int, void *, struct pt_regs *);
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       state = info->state;
+       
+       if (copy_from_user(&new_multi, in_multi,
+                          sizeof(struct serial_multiport_struct)))
+               return -EFAULT;
+       
+       if (new_multi.irq != state->irq || state->irq == 0 ||
+           !IRQ_ports[state->irq])
+               return -EINVAL;
+
+       multi = &rs_multiport[state->irq];
+       was_multi = (multi->port1 != 0);
+       
+       multi->port_monitor = new_multi.port_monitor;
+       
+       if (multi->port1)
+               release_region(multi->port1,1);
+       multi->port1 = new_multi.port1;
+       multi->mask1 = new_multi.mask1;
+       multi->match1 = new_multi.match1;
+       if (multi->port1)
+               request_region(multi->port1,1,"serial(multiport1)");
+
+       if (multi->port2)
+               release_region(multi->port2,1);
+       multi->port2 = new_multi.port2;
+       multi->mask2 = new_multi.mask2;
+       multi->match2 = new_multi.match2;
+       if (multi->port2)
+               request_region(multi->port2,1,"serial(multiport2)");
+
+       if (multi->port3)
+               release_region(multi->port3,1);
+       multi->port3 = new_multi.port3;
+       multi->mask3 = new_multi.mask3;
+       multi->match3 = new_multi.match3;
+       if (multi->port3)
+               request_region(multi->port3,1,"serial(multiport3)");
+
+       if (multi->port4)
+               release_region(multi->port4,1);
+       multi->port4 = new_multi.port4;
+       multi->mask4 = new_multi.mask4;
+       multi->match4 = new_multi.match4;
+       if (multi->port4)
+               request_region(multi->port4,1,"serial(multiport4)");
+
+       now_multi = (multi->port1 != 0);
+       
+       if (IRQ_ports[state->irq]->next_port &&
+           (was_multi != now_multi)) {
+               free_irq(state->irq, &IRQ_ports[state->irq]);
+               if (now_multi)
+                       handler = rs_interrupt_multi;
+               else
+                       handler = rs_interrupt;
+
+               retval = request_irq(state->irq, handler, SA_SHIRQ,
+                                    "serial", &IRQ_ports[state->irq]);
+               if (retval) {
+                       printk("Couldn't reallocate serial interrupt "
+                              "driver!!\n");
+               }
+       }
+       return 0;
+}
+#endif
+
+static int rs_ioctl(struct tty_struct *tty, struct file * file,
+                   unsigned int cmd, unsigned long arg)
+{
+       struct async_struct * info = (struct async_struct *)tty->driver_data;
+       struct async_icount cprev, cnow;        /* kernel counter temps */
+       struct serial_icounter_struct icount;
+       unsigned long flags;
+#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
+       int retval, tmp;
+#endif
+       
+       if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
+               return -ENODEV;
+
+       if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+           (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
+           (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
+               if (tty->flags & (1 << TTY_IO_ERROR))
+                   return -EIO;
+       }
+       
+       switch (cmd) {
+#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
+               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 (signal_pending(current))
+                               return -EINTR;
+                       if (!arg) {
+                               send_break(info, HZ/4); /* 1/4 second */
+                               if (signal_pending(current))
+                                       return -EINTR;
+                       }
+                       return 0;
+               case TCSBRKP:   /* support for POSIX tcsendbreak() */
+                       retval = tty_check_change(tty);
+                       if (retval)
+                               return retval;
+                       tty_wait_until_sent(tty, 0);
+                       if (signal_pending(current))
+                               return -EINTR;
+                       send_break(info, arg ? arg*(HZ/10) : HZ/4);
+                       if (signal_pending(current))
+                               return -EINTR;
+                       return 0;
+               case TIOCGSOFTCAR:
+                       tmp = C_CLOCAL(tty) ? 1 : 0;
+                       if (copy_to_user((void *)arg, &tmp, sizeof(int)))
+                               return -EFAULT;
+                       return 0;
+               case TIOCSSOFTCAR:
+                       if (copy_from_user(&tmp, (void *)arg, sizeof(int)))
+                               return -EFAULT;
+
+                       tty->termios->c_cflag =
+                               ((tty->termios->c_cflag & ~CLOCAL) |
+                                (tmp ? CLOCAL : 0));
+                       return 0;
+#endif
+               case TIOCMGET:
+                       return get_modem_info(info, (unsigned int *) arg);
+               case TIOCMBIS:
+               case TIOCMBIC:
+               case TIOCMSET:
+                       return set_modem_info(info, cmd, (unsigned int *) arg);
+               case TIOCGSERIAL:
+                       return get_serial_info(info,
+                                              (struct serial_struct *) arg);
+               case TIOCSSERIAL:
+                       return set_serial_info(info,
+                                              (struct serial_struct *) arg);
+               case TIOCSERCONFIG:
+                       return do_autoconfig(info);
+
+               case TIOCSERGETLSR: /* Get line status register */
+                       return get_lsr_info(info, (unsigned int *) arg);
+
+               case TIOCSERGSTRUCT:
+                       if (copy_to_user((struct async_struct *) arg,
+                                        info, sizeof(struct async_struct)))
+                               return -EFAULT;
+                       return 0;
+                               
+#ifdef CONFIG_SERIAL_MULTIPORT
+               case TIOCSERGETMULTI:
+                       return get_multiport_struct(info,
+                                      (struct serial_multiport_struct *) arg);
+               case TIOCSERSETMULTI:
+                       return set_multiport_struct(info,
+                                      (struct serial_multiport_struct *) arg);
+#endif
+                       
+               /*
+                * 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();
+                       /* note the counters on entry */
+                       cprev = info->state->icount;
+                       restore_flags(flags);
+                       /* Force modem status interrupts on */
+                       info->IER |= UART_IER_MSI;
+                       serial_out(info, UART_IER, info->IER);
+                       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->state->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->state->icount;
+                       restore_flags(flags);
+                       icount.cts = cnow.cts;
+                       icount.dsr = cnow.dsr;
+                       icount.rng = cnow.rng;
+                       icount.dcd = cnow.dcd;
+                       icount.rx = cnow.rx;
+                       icount.tx = cnow.tx;
+                       icount.frame = cnow.frame;
+                       icount.overrun = cnow.overrun;
+                       icount.parity = cnow.parity;
+                       icount.brk = cnow.brk;
+                       icount.buf_overrun = cnow.buf_overrun;
+                       
+                       if (copy_to_user((void *)arg, &icount, sizeof(icount)))
+                               return -EFAULT;
+                       return 0;
+               case TIOCSERGWILD:
+               case TIOCSERSWILD:
+                       /* "setserial -W" is called in Debian boot */
+                       printk ("TIOCSER?WILD ioctl obsolete, ignored.\n");
+                       return 0;
+
+               default:
+                       return -ENOIOCTLCMD;
+               }
+       return 0;
+}
+
+static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
+{
+       struct async_struct *info = (struct async_struct *)tty->driver_data;
+       unsigned long flags;
+       unsigned int cflag = tty->termios->c_cflag;
+       
+       if (   (cflag == old_termios->c_cflag)
+           && (   RELEVANT_IFLAG(tty->termios->c_iflag) 
+               == RELEVANT_IFLAG(old_termios->c_iflag)))
+         return;
+
+       change_speed(info, old_termios);
+
+       /* Handle transition to B0 status */
+       if ((old_termios->c_cflag & CBAUD) &&
+           !(cflag & CBAUD)) {
+               info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
+               save_flags(flags); cli();
+               serial_out(info, UART_MCR, info->MCR);
+               restore_flags(flags);
+       }
+       
+       /* Handle transition away from B0 status */
+       if (!(old_termios->c_cflag & CBAUD) &&
+           (cflag & CBAUD)) {
+               info->MCR |= UART_MCR_DTR;
+               if (!(tty->termios->c_cflag & CRTSCTS) || 
+                   !test_bit(TTY_THROTTLED, &tty->flags)) {
+                       info->MCR |= UART_MCR_RTS;
+               }
+               save_flags(flags); cli();
+               serial_out(info, UART_MCR, info->MCR);
+               restore_flags(flags);
+       }
+       
+       /* Handle turning off CRTSCTS */
+       if ((old_termios->c_cflag & CRTSCTS) &&
+           !(tty->termios->c_cflag & CRTSCTS)) {
+               tty->hw_stopped = 0;
+               rs_start(tty);
+       }
+
+#if 0
+       /*
+        * No need to wake up processes in open wait, since they
+        * sample the CLOCAL flag once, and don't recheck it.
+        * XXX  It's not clear whether the current behavior is correct
+        * or not.  Hence, this may change.....
+        */
+       if (!(old_termios->c_cflag & CLOCAL) &&
+           (tty->termios->c_cflag & CLOCAL))
+               wake_up_interruptible(&info->open_wait);
+#endif
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_close()
+ * 
+ * This routine is called when the serial port gets closed.  First, we
+ * wait for the last remaining data to be sent.  Then, we unlink its
+ * async structure from the interrupt chain if necessary, and we free
+ * that IRQ if nothing is left in the chain.
+ * ------------------------------------------------------------
+ */
+static void rs_close(struct tty_struct *tty, struct file * filp)
+{
+       struct async_struct * info = (struct async_struct *)tty->driver_data;
+       struct serial_state *state;
+       unsigned long flags;
+
+       if (!info || serial_paranoia_check(info, tty->device, "rs_close"))
+               return;
+
+       state = info->state;
+       
+       save_flags(flags); cli();
+       
+       if (tty_hung_up_p(filp)) {
+               DBG_CNT("before DEC-hung");
+               MOD_DEC_USE_COUNT;
+               restore_flags(flags);
+               return;
+       }
+       
+#ifdef SERIAL_DEBUG_OPEN
+       printk("rs_close ttys%d, count = %d\n", info->line, state->count);
+#endif
+       if ((tty->count == 1) && (state->count != 1)) {
+               /*
+                * Uh, oh.  tty->count is 1, which means that the tty
+                * structure will be freed.  state->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("rs_close: bad serial port count; tty->count is 1, "
+                      "state->count is %d\n", state->count);
+               state->count = 1;
+       }
+       if (--state->count < 0) {
+               printk("rs_close: bad serial port count for ttys%d: %d\n",
+                      info->line, state->count);
+               state->count = 0;
+       }
+       if (state->count) {
+               DBG_CNT("before DEC-2");
+               MOD_DEC_USE_COUNT;
+               restore_flags(flags);
+               return;
+       }
+       info->flags |= ASYNC_CLOSING;
+       restore_flags(flags);
+       /*
+        * Save the termios structure, since this port may have
+        * separate termios for callout and dialin.
+        */
+       if (info->flags & ASYNC_NORMAL_ACTIVE)
+               info->state->normal_termios = *tty->termios;
+       if (info->flags & ASYNC_CALLOUT_ACTIVE)
+               info->state->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 (state->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+               tty_wait_until_sent(tty, state->closing_wait);
+       /*
+        * At this point we stop accepting input.  To do this, we
+        * disable the receive line status interrupts, and tell the
+        * interrupt driver to stop checking the data ready bit in the
+        * line status register.
+        */
+       info->IER &= ~UART_IER_RLSI;
+       info->read_status_mask &= ~UART_LSR_DR;
+       if (info->flags & ASYNC_INITIALIZED) {
+               serial_out(info, UART_IER, info->IER);
+               /*
+                * Before we drop DTR, make sure the UART transmitter
+                * has completely drained; this is especially
+                * important if there is a transmit FIFO!
+                */
+               rs_wait_until_sent(tty, info->timeout);
+       }
+       shutdown(info);
+       if (tty->driver.flush_buffer)
+               tty->driver.flush_buffer(tty);
+       tty_ldisc_flush(tty);
+       tty->closing = 0;
+       info->event = 0;
+       info->tty = 0;
+       if (info->blocked_open) {
+               if (state->close_delay) {
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       schedule_timeout(state->close_delay);
+               }
+               wake_up_interruptible(&info->open_wait);
+       }
+       info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
+                        ASYNC_CLOSING);
+       wake_up_interruptible(&info->close_wait);
+       MOD_DEC_USE_COUNT;
+}
+
+/*
+ * rs_wait_until_sent() --- wait until the transmitter is empty
+ */
+static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+       struct async_struct * info = (struct async_struct *)tty->driver_data;
+       unsigned long orig_jiffies, char_time;
+       int lsr;
+       
+       if (serial_paranoia_check(info, tty->device, "rs_wait_until_sent"))
+               return;
+
+       if (info->state->type == PORT_UNKNOWN)
+               return;
+
+       if (info->xmit_fifo_size == 0)
+               return; /* Just in case.... */
+
+       orig_jiffies = jiffies;
+       /*
+        * Set the check interval to be 1/5 of the estimated time to
+        * send a single character, and make it at least 1.  The check
+        * interval should also be less than the timeout.
+        * 
+        * Note: we have to use pretty tight timings here to satisfy
+        * the NIST-PCTS.
+        */
+       char_time = (info->timeout - HZ/50) / info->xmit_fifo_size;
+       char_time = char_time / 5;
+       if (char_time == 0)
+               char_time = 1;
+       if (timeout && timeout < char_time)
+               char_time = timeout;
+       /*
+        * If the transmitter hasn't cleared in twice the approximate
+        * amount of time to send the entire FIFO, it probably won't
+        * ever clear.  This assumes the UART isn't doing flow
+        * control, which is currently the case.  Hence, if it ever
+        * takes longer than info->timeout, this is probably due to a
+        * UART bug of some kind.  So, we clamp the timeout parameter at
+        * 2*info->timeout.
+        */
+       if (!timeout || timeout > 2*info->timeout)
+               timeout = 2*info->timeout;
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+       printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time);
+       printk("jiff=%lu...", jiffies);
+#endif
+       while (!((lsr = serial_inp(info, UART_LSR)) & UART_LSR_TEMT)) {
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+               printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
+#endif
+               set_current_state(TASK_INTERRUPTIBLE);
+               schedule_timeout(char_time);
+               if (signal_pending(current))
+                       break;
+               if (timeout && time_after(jiffies, orig_jiffies + timeout))
+                       break;
+       }
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+       printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
+#endif
+}
+
+/*
+ * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
+ */
+static void rs_hangup(struct tty_struct *tty)
+{
+       struct async_struct * info = (struct async_struct *)tty->driver_data;
+       struct serial_state *state = info->state;
+       
+       if (serial_paranoia_check(info, tty->device, "rs_hangup"))
+               return;
+
+       state = info->state;
+       
+       rs_flush_buffer(tty);
+       if (info->flags & ASYNC_CLOSING)
+               return;
+       shutdown(info);
+       info->event = 0;
+       state->count = 0;
+       info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+       info->tty = 0;
+       wake_up_interruptible(&info->open_wait);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_open() and friends
+ * ------------------------------------------------------------
+ */
+static int block_til_ready(struct tty_struct *tty, struct file * filp,
+                          struct async_struct *info)
+{
+       DECLARE_WAITQUEUE(wait, current);
+       struct serial_state *state = info->state;
+       int             retval;
+       int             do_clocal = 0, extra_count = 0;
+       unsigned long   flags;
+
+       /*
+        * If the device is in the middle of being closed, then block
+        * until it's done, and then try again.
+        */
+       if (tty_hung_up_p(filp) ||
+           (info->flags & ASYNC_CLOSING)) {
+               if (info->flags & ASYNC_CLOSING)
+                       interruptible_sleep_on(&info->close_wait);
+#ifdef SERIAL_DO_RESTART
+               return ((info->flags & ASYNC_HUP_NOTIFY) ?
+                       -EAGAIN : -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 (state->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, state->count is dropped by one, so that
+        * rs_close() knows when to free things.  We restore it upon
+        * exit, either normal or abnormal.
+        */
+       retval = 0;
+       add_wait_queue(&info->open_wait, &wait);
+#ifdef SERIAL_DEBUG_OPEN
+       printk("block_til_ready before block: ttys%d, count = %d\n",
+              state->line, state->count);
+#endif
+       save_flags(flags); cli();
+       if (!tty_hung_up_p(filp)) {
+               extra_count = 1;
+               state->count--;
+       }
+       restore_flags(flags);
+       info->blocked_open++;
+       while (1) {
+               save_flags(flags); cli();
+               if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
+                   (tty->termios->c_cflag & CBAUD))
+                       serial_out(info, UART_MCR,
+                                  serial_inp(info, UART_MCR) |
+                                  (UART_MCR_DTR | UART_MCR_RTS));
+               restore_flags(flags);
+               set_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 || (serial_in(info, UART_MSR) &
+                                  UART_MSR_DCD)))
+                       break;
+               if (signal_pending(current)) {
+                       retval = -ERESTARTSYS;
+                       break;
+               }
+#ifdef SERIAL_DEBUG_OPEN
+               printk("block_til_ready blocking: ttys%d, count = %d\n",
+                      info->line, state->count);
+#endif
+               schedule();
+       }
+       set_current_state(TASK_RUNNING);
+       remove_wait_queue(&info->open_wait, &wait);
+       if (extra_count)
+               state->count++;
+       info->blocked_open--;
+#ifdef SERIAL_DEBUG_OPEN
+       printk("block_til_ready after blocking: ttys%d, count = %d\n",
+              info->line, state->count);
+#endif
+       if (retval)
+               return retval;
+       info->flags |= ASYNC_NORMAL_ACTIVE;
+       return 0;
+}
+
+static int get_async_struct(int line, struct async_struct **ret_info)
+{
+       struct async_struct *info;
+       struct serial_state *sstate;
+
+       sstate = rs_table + line;
+       sstate->count++;
+       if (sstate->info) {
+               *ret_info = sstate->info;
+               return 0;
+       }
+       info = kmalloc(sizeof(struct async_struct), GFP_KERNEL);
+       if (!info) {
+               sstate->count--;
+               return -ENOMEM;
+       }
+       memset(info, 0, sizeof(struct async_struct));
+       init_waitqueue_head(&info->open_wait);
+       init_waitqueue_head(&info->close_wait);
+       init_waitqueue_head(&info->delta_msr_wait);
+       info->magic = SERIAL_MAGIC;
+       info->port = sstate->port;
+       info->flags = sstate->flags;
+       info->io_type = sstate->io_type;
+       info->iomem_base = sstate->iomem_base;
+       info->iomem_reg_shift = sstate->iomem_reg_shift;
+       info->xmit_fifo_size = sstate->xmit_fifo_size;
+       info->line = line;
+       info->tqueue.routine = do_softint;
+       info->tqueue.data = info;
+       info->state = sstate;
+       if (sstate->info) {
+               kfree(info);
+               *ret_info = sstate->info;
+               return 0;
+       }
+       *ret_info = sstate->info = info;
+       return 0;
+}
+
+/*
+ * This routine is called whenever a serial port is opened.  It
+ * enables interrupts for a serial port, linking in its async structure into
+ * the IRQ chain.   It also performs the serial-specific
+ * initialization for the tty structure.
+ *
+ * Note that on failure, we don't decrement the module use count - the tty
+ * later will call rs_close, which will decrement it for us as long as
+ * tty->driver_data is set non-NULL. --rmk
+ */
+static int rs_open(struct tty_struct *tty, struct file * filp)
+{
+       struct async_struct     *info;
+       int                     retval, line;
+       unsigned long           page;
+
+       MOD_INC_USE_COUNT;
+       line = MINOR(tty->device) - tty->driver.minor_start;
+       if ((line < 0) || (line >= NR_PORTS)) {
+               MOD_DEC_USE_COUNT;
+               return -ENODEV;
+       }
+       retval = get_async_struct(line, &info);
+       if (retval) {
+               MOD_DEC_USE_COUNT;
+               return retval;
+       }
+       tty->driver_data = info;
+       info->tty = tty;
+       if (serial_paranoia_check(info, tty->device, "rs_open"))
+               return -ENODEV;
+
+#ifdef SERIAL_DEBUG_OPEN
+       printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line,
+              info->state->count);
+#endif
+#if (LINUX_VERSION_CODE > 0x20100)
+       info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+#endif
+
+       /*
+        *      This relies on lock_kernel() stuff so wants tidying for 2.5
+        */
+       if (!tmp_buf) {
+               page = get_zeroed_page(GFP_KERNEL);
+               if (!page)
+                       return -ENOMEM;
+               if (tmp_buf)
+                       free_page(page);
+               else
+                       tmp_buf = (unsigned char *) page;
+       }
+
+       /*
+        * If the port is the middle of closing, bail out now
+        */
+       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
+               return ((info->flags & ASYNC_HUP_NOTIFY) ?
+                       -EAGAIN : -ERESTARTSYS);
+#else
+               return -EAGAIN;
+#endif
+       }
+
+       /*
+        * Start up serial port
+        */
+       retval = startup(info);
+       if (retval)
+               return retval;
+
+       retval = block_til_ready(tty, filp, info);
+       if (retval) {
+#ifdef SERIAL_DEBUG_OPEN
+               printk("rs_open returning after block_til_ready with %d\n",
+                      retval);
+#endif
+               return retval;
+       }
+
+       if ((info->state->count == 1) &&
+           (info->flags & ASYNC_SPLIT_TERMIOS)) {
+               if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+                       *tty->termios = info->state->normal_termios;
+               else 
+                       *tty->termios = info->state->callout_termios;
+               change_speed(info, 0);
+       }
+#ifdef CONFIG_SERIAL_CONSOLE
+       if (sercons.cflag && sercons.index == line) {
+               tty->termios->c_cflag = sercons.cflag;
+               sercons.cflag = 0;
+               change_speed(info, 0);
+       }
+#endif
+       info->session = current->session;
+       info->pgrp = current->pgrp;
+
+#ifdef SERIAL_DEBUG_OPEN
+       printk("rs_open ttys%d successful...", info->line);
+#endif
+       return 0;
+}
+
+/*
+ * /proc fs routines....
+ */
+
+static inline int line_info(char *buf, struct serial_state *state)
+{
+       struct async_struct *info = state->info, scr_info;
+       char    stat_buf[30], control, status;
+       int     ret;
+       unsigned long flags;
+
+       /*
+        * Return zero characters for ports not claimed by driver.
+        */
+       if (state->type == PORT_UNKNOWN) {
+               return 0;       /* ignore unused ports */
+       }
+
+       ret = sprintf(buf, "%d: uart:%s port:%lX irq:%d",
+                     state->line, uart_config[state->type].name, 
+                     (state->port ? state->port : (long)state->iomem_base),
+                     state->irq);
+
+       /*
+        * Figure out the current RS-232 lines
+        */
+       if (!info) {
+               info = &scr_info;       /* This is just for serial_{in,out} */
+
+               info->magic = SERIAL_MAGIC;
+               info->port = state->port;
+               info->flags = state->flags;
+               info->hub6 = state->hub6;
+               info->io_type = state->io_type;
+               info->iomem_base = state->iomem_base;
+               info->iomem_reg_shift = state->iomem_reg_shift;
+               info->quot = 0;
+               info->tty = 0;
+       }
+       save_flags(flags); cli();
+       status = serial_in(info, UART_MSR);
+       control = info != &scr_info ? info->MCR : serial_in(info, UART_MCR);
+       restore_flags(flags); 
+
+       stat_buf[0] = 0;
+       stat_buf[1] = 0;
+       if (control & UART_MCR_RTS)
+               strcat(stat_buf, "|RTS");
+       if (status & UART_MSR_CTS)
+               strcat(stat_buf, "|CTS");
+       if (control & UART_MCR_DTR)
+               strcat(stat_buf, "|DTR");
+       if (status & UART_MSR_DSR)
+               strcat(stat_buf, "|DSR");
+       if (status & UART_MSR_DCD)
+               strcat(stat_buf, "|CD");
+       if (status & UART_MSR_RI)
+               strcat(stat_buf, "|RI");
+
+       if (info->quot) {
+               ret += sprintf(buf+ret, " baud:%d",
+                              state->baud_base / info->quot);
+       }
+
+       ret += sprintf(buf+ret, " tx:%d rx:%d",
+                     state->icount.tx, state->icount.rx);
+
+       if (state->icount.frame)
+               ret += sprintf(buf+ret, " fe:%d", state->icount.frame);
+       
+       if (state->icount.parity)
+               ret += sprintf(buf+ret, " pe:%d", state->icount.parity);
+       
+       if (state->icount.brk)
+               ret += sprintf(buf+ret, " brk:%d", state->icount.brk);  
+
+       if (state->icount.overrun)
+               ret += sprintf(buf+ret, " oe:%d", state->icount.overrun);
+
+       /*
+        * Last thing is the RS-232 status lines
+        */
+       ret += sprintf(buf+ret, " %s\n", stat_buf+1);
+       return ret;
+}
+
+static int rs_read_proc(char *page, char **start, off_t off, int count,
+                       int *eof, void *data)
+{
+       int i, len = 0, l;
+       off_t   begin = 0;
+
+       len += sprintf(page, "serinfo:1.0 driver:%s%s revision:%s\n",
+                      serial_version, LOCAL_VERSTRING, serial_revdate);
+       for (i = 0; i < NR_PORTS && len < 4000; i++) {
+               l = line_info(page + len, &rs_table[i]);
+               len += l;
+               if (len+begin > off+count)
+                       goto done;
+               if (len+begin < off) {
+                       begin += len;
+                       len = 0;
+               }
+       }
+       *eof = 1;
+done:
+       if (off >= len+begin)
+               return 0;
+       *start = page + (off-begin);
+       return ((count < begin+len-off) ? count : begin+len-off);
+}
+
+/*
+ * ---------------------------------------------------------------------
+ * rs_init() and friends
+ *
+ * rs_init() is called at boot-time to initialize the serial driver.
+ * ---------------------------------------------------------------------
+ */
+
+/*
+ * This routine prints out the appropriate serial driver version
+ * number, and identifies which options were configured into this
+ * driver.
+ */
+static char serial_options[] __initdata =
+#ifdef CONFIG_HUB6
+       " HUB-6"
+#define SERIAL_OPT
+#endif
+#ifdef CONFIG_SERIAL_MANY_PORTS
+       " MANY_PORTS"
+#define SERIAL_OPT
+#endif
+#ifdef CONFIG_SERIAL_MULTIPORT
+       " MULTIPORT"
+#define SERIAL_OPT
+#endif
+#ifdef CONFIG_SERIAL_SHARE_IRQ
+       " SHARE_IRQ"
+#define SERIAL_OPT
+#endif
+#ifdef CONFIG_SERIAL_DETECT_IRQ
+       " DETECT_IRQ"
+#define SERIAL_OPT
+#endif
+#ifdef ENABLE_SERIAL_PCI
+       " SERIAL_PCI"
+#define SERIAL_OPT
+#endif
+#ifdef ENABLE_SERIAL_PNP
+       " ISAPNP"
+#define SERIAL_OPT
+#endif
+#ifdef ENABLE_SERIAL_ACPI
+       " SERIAL_ACPI"
+#define SERIAL_OPT
+#endif
+#ifdef SERIAL_OPT
+       " enabled\n";
+#else
+       " no serial options enabled\n";
+#endif
+#undef SERIAL_OPT
+
+static _INLINE_ void show_serial_version(void)
+{
+       printk(KERN_INFO "%s version %s%s (%s) with%s", serial_name,
+              serial_version, LOCAL_VERSTRING, serial_revdate,
+              serial_options);
+}
+
+/*
+ * This routine detect the IRQ of a serial port by clearing OUT2 when
+ * no UART interrupt are requested (IER = 0) (*GPL*). This seems to work at
+ * each time, as long as no other device permanently request the IRQ.
+ * If no IRQ is detected, or multiple IRQ appear, this function returns 0.
+ * The variable "state" and the field "state->port" should not be null.
+ */
+static unsigned detect_uart_irq (struct serial_state * state)
+{
+       int irq;
+       unsigned long irqs;
+       unsigned char save_mcr, save_ier;
+       struct async_struct scr_info; /* serial_{in,out} because HUB6 */
+
+#ifdef CONFIG_SERIAL_MANY_PORTS
+       unsigned char save_ICP=0; /* no warning */
+       unsigned short ICP=0;
+
+       if (state->flags & ASYNC_FOURPORT)  {
+               ICP = (state->port & 0xFE0) | 0x01F;
+               save_ICP = inb_p(ICP);
+               outb_p(0x80, ICP);
+               (void) inb_p(ICP);
+       }
+#endif
+       scr_info.magic = SERIAL_MAGIC;
+       scr_info.state = state;
+       scr_info.port = state->port;
+       scr_info.flags = state->flags;
+#ifdef CONFIG_HUB6
+       scr_info.hub6 = state->hub6;
+#endif
+       scr_info.io_type = state->io_type;
+       scr_info.iomem_base = state->iomem_base;
+       scr_info.iomem_reg_shift = state->iomem_reg_shift;
+
+       /* forget possible initially masked and pending IRQ */
+       probe_irq_off(probe_irq_on());
+       save_mcr = serial_inp(&scr_info, UART_MCR);
+       save_ier = serial_inp(&scr_info, UART_IER);
+       serial_outp(&scr_info, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2);
+       
+       irqs = probe_irq_on();
+       serial_outp(&scr_info, UART_MCR, 0);
+       udelay (10);
+       if (state->flags & ASYNC_FOURPORT)  {
+               serial_outp(&scr_info, UART_MCR,
+                           UART_MCR_DTR | UART_MCR_RTS);
+       } else {
+               serial_outp(&scr_info, UART_MCR,
+                           UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2);
+       }
+       serial_outp(&scr_info, UART_IER, 0x0f); /* enable all intrs */
+       (void)serial_inp(&scr_info, UART_LSR);
+       (void)serial_inp(&scr_info, UART_RX);
+       (void)serial_inp(&scr_info, UART_IIR);
+       (void)serial_inp(&scr_info, UART_MSR);
+       serial_outp(&scr_info, UART_TX, 0xFF);
+       udelay (20);
+       irq = probe_irq_off(irqs);
+
+       serial_outp(&scr_info, UART_MCR, save_mcr);
+       serial_outp(&scr_info, UART_IER, save_ier);
+#ifdef CONFIG_SERIAL_MANY_PORTS
+       if (state->flags & ASYNC_FOURPORT)
+               outb_p(save_ICP, ICP);
+#endif
+       return (irq > 0)? irq : 0;
+}
+
+/*
+ * This is a quickie test to see how big the FIFO is.
+ * It doesn't work at all the time, more's the pity.
+ */
+static int size_fifo(struct async_struct *info)
+{
+       unsigned char old_fcr, old_mcr, old_dll, old_dlm;
+       int count;
+
+       old_fcr = serial_inp(info, UART_FCR);
+       old_mcr = serial_inp(info, UART_MCR);
+       serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO |
+                   UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
+       serial_outp(info, UART_MCR, UART_MCR_LOOP);
+       serial_outp(info, UART_LCR, UART_LCR_DLAB);
+       old_dll = serial_inp(info, UART_DLL);
+       old_dlm = serial_inp(info, UART_DLM);
+       serial_outp(info, UART_DLL, 0x01);
+       serial_outp(info, UART_DLM, 0x00);
+       serial_outp(info, UART_LCR, 0x03);
+       for (count = 0; count < 256; count++)
+               serial_outp(info, UART_TX, count);
+       mdelay(20);
+       for (count = 0; (serial_inp(info, UART_LSR) & UART_LSR_DR) &&
+            (count < 256); count++)
+               serial_inp(info, UART_RX);
+       serial_outp(info, UART_FCR, old_fcr);
+       serial_outp(info, UART_MCR, old_mcr);
+       serial_outp(info, UART_LCR, UART_LCR_DLAB);
+       serial_outp(info, UART_DLL, old_dll);
+       serial_outp(info, UART_DLM, old_dlm);
+
+       return count;
+}
+
+/*
+ * This is a helper routine to autodetect StarTech/Exar/Oxsemi UART's.
+ * When this function is called we know it is at least a StarTech
+ * 16650 V2, but it might be one of several StarTech UARTs, or one of
+ * its clones.  (We treat the broken original StarTech 16650 V1 as a
+ * 16550, and why not?  Startech doesn't seem to even acknowledge its
+ * existence.)
+ * 
+ * What evil have men's minds wrought...
+ */
+static void autoconfig_startech_uarts(struct async_struct *info,
+                                     struct serial_state *state,
+                                     unsigned long flags)
+{
+       unsigned char scratch, scratch2, scratch3, scratch4;
+
+       /*
+        * First we check to see if it's an Oxford Semiconductor UART.
+        *
+        * If we have to do this here because some non-National
+        * Semiconductor clone chips lock up if you try writing to the
+        * LSR register (which serial_icr_read does)
+        */
+       if (state->type == PORT_16550A) {
+               /*
+                * EFR [4] must be set else this test fails
+                *
+                * This shouldn't be necessary, but Mike Hudson
+                * (Exoray@isys.ca) claims that it's needed for 952
+                * dual UART's (which are not recommended for new designs).
+                */
+               info->ACR = 0;
+               serial_out(info, UART_LCR, 0xBF);
+               serial_out(info, UART_EFR, 0x10);
+               serial_out(info, UART_LCR, 0x00);
+               /* Check for Oxford Semiconductor 16C950 */
+               scratch = serial_icr_read(info, UART_ID1);
+               scratch2 = serial_icr_read(info, UART_ID2);
+               scratch3 = serial_icr_read(info, UART_ID3);
+               
+               if (scratch == 0x16 && scratch2 == 0xC9 &&
+                   (scratch3 == 0x50 || scratch3 == 0x52 ||
+                    scratch3 == 0x54)) {
+                       state->type = PORT_16C950;
+                       state->revision = serial_icr_read(info, UART_REV) |
+                               (scratch3 << 8);
+                       return;
+               }
+       }
+       
+       /*
+        * We check for a XR16C850 by setting DLL and DLM to 0, and
+        * then reading back DLL and DLM.  If DLM reads back 0x10,
+        * then the UART is a XR16C850 and the DLL contains the chip
+        * revision.  If DLM reads back 0x14, then the UART is a
+        * XR16C854.
+        * 
+        */
+
+       /* Save the DLL and DLM */
+
+       serial_outp(info, UART_LCR, UART_LCR_DLAB);
+       scratch3 = serial_inp(info, UART_DLL);
+       scratch4 = serial_inp(info, UART_DLM);
+
+       serial_outp(info, UART_DLL, 0);
+       serial_outp(info, UART_DLM, 0);
+       scratch2 = serial_inp(info, UART_DLL);
+       scratch = serial_inp(info, UART_DLM);
+       serial_outp(info, UART_LCR, 0);
+
+       if (scratch == 0x10 || scratch == 0x14) {
+               if (scratch == 0x10)
+                       state->revision = scratch2;
+               state->type = PORT_16850;
+               return;
+       }
+
+       /* Restore the DLL and DLM */
+
+       serial_outp(info, UART_LCR, UART_LCR_DLAB);
+       serial_outp(info, UART_DLL, scratch3);
+       serial_outp(info, UART_DLM, scratch4);
+       serial_outp(info, UART_LCR, 0);
+       /*
+        * We distinguish between the '654 and the '650 by counting
+        * how many bytes are in the FIFO.  I'm using this for now,
+        * since that's the technique that was sent to me in the
+        * serial driver update, but I'm not convinced this works.
+        * I've had problems doing this in the past.  -TYT
+        */
+       if (size_fifo(info) == 64)
+               state->type = PORT_16654;
+       else
+               state->type = PORT_16650V2;
+}
+
+/*
+ * This routine is called by rs_init() to initialize a specific serial
+ * port.  It determines what type of UART chip this serial port is
+ * using: 8250, 16450, 16550, 16550A.  The important question is
+ * whether or not this UART is a 16550A or not, since this will
+ * determine whether or not we can use its FIFO features or not.
+ */
+static void autoconfig(struct serial_state * state)
+{
+       unsigned char status1, status2, scratch, scratch2, scratch3;
+       unsigned char save_lcr, save_mcr;
+       struct async_struct *info, scr_info;
+       unsigned long flags;
+
+       state->type = PORT_UNKNOWN;
+
+#ifdef SERIAL_DEBUG_AUTOCONF
+       printk("Testing ttyS%d (0x%04lx, 0x%04x)...\n", state->line,
+              state->port, (unsigned) state->iomem_base);
+#endif
+       
+       if (!CONFIGURED_SERIAL_PORT(state))
+               return;
+               
+       info = &scr_info;       /* This is just for serial_{in,out} */
+
+       info->magic = SERIAL_MAGIC;
+       info->state = state;
+       info->port = state->port;
+       info->flags = state->flags;
+#ifdef CONFIG_HUB6
+       info->hub6 = state->hub6;
+#endif
+       info->io_type = state->io_type;
+       info->iomem_base = state->iomem_base;
+       info->iomem_reg_shift = state->iomem_reg_shift;
+
+       save_flags(flags); cli();
+       
+       if (!(state->flags & ASYNC_BUGGY_UART) &&
+           !state->iomem_base) {
+               /*
+                * Do a simple existence test first; if we fail this,
+                * there's no point trying anything else.
+                * 
+                * 0x80 is used as a nonsense port to prevent against
+                * false positives due to ISA bus float.  The
+                * assumption is that 0x80 is a non-existent port;
+                * which should be safe since include/asm/io.h also
+                * makes this assumption.
+                */
+               scratch = serial_inp(info, UART_IER);
+               serial_outp(info, UART_IER, 0);
+#ifdef __i386__
+               outb(0xff, 0x080);
+#endif
+               scratch2 = serial_inp(info, UART_IER);
+               serial_outp(info, UART_IER, 0x0F);
+#ifdef __i386__
+               outb(0, 0x080);
+#endif
+               scratch3 = serial_inp(info, UART_IER);
+               serial_outp(info, UART_IER, scratch);
+               if (scratch2 || scratch3 != 0x0F) {
+#ifdef SERIAL_DEBUG_AUTOCONF
+                       printk("serial: ttyS%d: simple autoconfig failed "
+                              "(%02x, %02x)\n", state->line, 
+                              scratch2, scratch3);
+#endif
+                       restore_flags(flags);
+                       return;         /* We failed; there's nothing here */
+               }
+       }
+
+       save_mcr = serial_in(info, UART_MCR);
+       save_lcr = serial_in(info, UART_LCR);
+
+       /* 
+        * Check to see if a UART is really there.  Certain broken
+        * internal modems based on the Rockwell chipset fail this
+        * test, because they apparently don't implement the loopback
+        * test mode.  So this test is skipped on the COM 1 through
+        * COM 4 ports.  This *should* be safe, since no board
+        * manufacturer would be stupid enough to design a board
+        * that conflicts with COM 1-4 --- we hope!
+        */
+       if (!(state->flags & ASYNC_SKIP_TEST)) {
+               serial_outp(info, UART_MCR, UART_MCR_LOOP | 0x0A);
+               status1 = serial_inp(info, UART_MSR) & 0xF0;
+               serial_outp(info, UART_MCR, save_mcr);
+               if (status1 != 0x90) {
+#ifdef SERIAL_DEBUG_AUTOCONF
+                       printk("serial: ttyS%d: no UART loopback failed\n",
+                              state->line);
+#endif
+                       restore_flags(flags);
+                       return;
+               }
+       }
+       serial_outp(info, UART_LCR, 0xBF); /* set up for StarTech test */
+       serial_outp(info, UART_EFR, 0); /* EFR is the same as FCR */
+       serial_outp(info, UART_LCR, 0);
+       serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
+       scratch = serial_in(info, UART_IIR) >> 6;
+       switch (scratch) {
+               case 0:
+                       state->type = PORT_16450;
+                       break;
+               case 1:
+                       state->type = PORT_UNKNOWN;
+                       break;
+               case 2:
+                       state->type = PORT_16550;
+                       break;
+               case 3:
+                       state->type = PORT_16550A;
+                       break;
+       }
+       if (state->type == PORT_16550A) {
+               /* Check for Startech UART's */
+               serial_outp(info, UART_LCR, UART_LCR_DLAB);
+               if (serial_in(info, UART_EFR) == 0) {
+                       serial_outp(info, UART_EFR, 0xA8);
+                       if (serial_in(info, UART_EFR) == 0) {
+                               /* We are a NS16552D/Motorola
+                                * 8xxx DUART, stop. */
+                               goto out;
+                       }
+                       state->type = PORT_16650;
+                       serial_outp(info, UART_EFR, 0);
+               } else {
+                       serial_outp(info, UART_LCR, 0xBF);
+                       if (serial_in(info, UART_EFR) == 0)
+                               autoconfig_startech_uarts(info, state, flags);
+               }
+       }
+       if (state->type == PORT_16550A) {
+               /* Check for TI 16750 */
+               serial_outp(info, UART_LCR, save_lcr | UART_LCR_DLAB);
+               serial_outp(info, UART_FCR,
+                           UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
+               scratch = serial_in(info, UART_IIR) >> 5;
+               if (scratch == 7) {
+                       /*
+                        * If this is a 16750, and not a cheap UART
+                        * clone, then it should only go into 64 byte
+                        * mode if the UART_FCR7_64BYTE bit was set
+                        * while UART_LCR_DLAB was latched.
+                        */
+                       serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
+                       serial_outp(info, UART_LCR, 0);
+                       serial_outp(info, UART_FCR,
+                                   UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
+                       scratch = serial_in(info, UART_IIR) >> 5;
+                       if (scratch == 6)
+                               state->type = PORT_16750;
+               }
+               serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
+       }
+#if defined(CONFIG_SERIAL_RSA) && defined(MODULE)
+       if (state->type == PORT_16550A) {
+               int i;
+
+               for (i = 0 ; i < PORT_RSA_MAX ; ++i) {
+                       if (!probe_rsa[i] && !force_rsa[i])
+                               break;
+                       if (((probe_rsa[i] != state->port) ||
+                            check_region(state->port + UART_RSA_BASE, 16)) &&
+                           (force_rsa[i] != state->port))
+                               continue;
+                       if (!enable_rsa(info))
+                               continue;
+                       state->type = PORT_RSA;
+                       state->baud_base = SERIAL_RSA_BAUD_BASE;
+                       break;
+               }
+       }
+#endif
+out:
+       serial_outp(info, UART_LCR, save_lcr);
+       if (state->type == PORT_16450) {
+               scratch = serial_in(info, UART_SCR);
+               serial_outp(info, UART_SCR, 0xa5);
+               status1 = serial_in(info, UART_SCR);
+               serial_outp(info, UART_SCR, 0x5a);
+               status2 = serial_in(info, UART_SCR);
+               serial_outp(info, UART_SCR, scratch);
+
+               if ((status1 != 0xa5) || (status2 != 0x5a))
+                       state->type = PORT_8250;
+       }
+       state->xmit_fifo_size = uart_config[state->type].dfl_xmit_fifo_size;
+
+       if (state->type == PORT_UNKNOWN) {
+               restore_flags(flags);
+               return;
+       }
+
+       if (info->port) {
+#ifdef CONFIG_SERIAL_RSA
+               if (state->type == PORT_RSA)
+                       request_region(info->port + UART_RSA_BASE, 16,
+                                      "serial_rsa(auto)");
+               else
+#endif
+                       request_region(info->port,8,"serial(auto)");
+       }
+
+       /*
+        * Reset the UART.
+        */
+#ifdef CONFIG_SERIAL_RSA
+       if (state->type == PORT_RSA)
+               serial_outp(info, UART_RSA_FRR, 0);
+#endif
+       serial_outp(info, UART_MCR, save_mcr);
+       serial_outp(info, UART_FCR, (UART_FCR_ENABLE_FIFO |
+                                    UART_FCR_CLEAR_RCVR |
+                                    UART_FCR_CLEAR_XMIT));
+       serial_outp(info, UART_FCR, 0);
+       (void)serial_in(info, UART_RX);
+       serial_outp(info, UART_IER, 0);
+       
+       restore_flags(flags);
+}
+
+int register_serial(struct serial_struct *req);
+void unregister_serial(int line);
+
+#if (LINUX_VERSION_CODE > 0x20100)
+EXPORT_SYMBOL(register_serial);
+EXPORT_SYMBOL(unregister_serial);
+#else
+static struct symbol_table serial_syms = {
+#include <linux/symtab_begin.h>
+       X(register_serial),
+       X(unregister_serial),
+#include <linux/symtab_end.h>
+};
+#endif
+
+
+#if defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP) 
+
+static void __devinit printk_pnp_dev_id(unsigned short vendor,
+                                    unsigned short device)
+{
+       printk("%c%c%c%x%x%x%x",
+              'A' + ((vendor >> 2) & 0x3f) - 1,
+              'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1,
+              'A' + ((vendor >> 8) & 0x1f) - 1,
+              (device >> 4) & 0x0f,
+              device & 0x0f,
+              (device >> 12) & 0x0f,
+              (device >> 8) & 0x0f);
+}
+
+static _INLINE_ int get_pci_port(struct pci_dev *dev,
+                                 struct pci_board *board,
+                                 struct serial_struct *req,
+                                 int idx)
+{
+       unsigned long port;
+       int base_idx;
+       int max_port;
+       int offset;
+
+       base_idx = SPCI_FL_GET_BASE(board->flags);
+       if (board->flags & SPCI_FL_BASE_TABLE)
+               base_idx += idx;
+
+       if (board->flags & SPCI_FL_REGION_SZ_CAP) {
+               max_port = pci_resource_len(dev, base_idx) / 8;
+               if (idx >= max_port)
+                       return 1;
+       }
+                       
+       offset = board->first_uart_offset;
+
+       /* Timedia/SUNIX uses a mixture of BARs and offsets */
+       /* Ugh, this is ugly as all hell --- TYT */
+       if(dev->vendor == PCI_VENDOR_ID_TIMEDIA )  /* 0x1409 */
+               switch(idx) {
+                       case 0: base_idx=0;
+                               break;
+                       case 1: base_idx=0; offset=8;
+                               break;
+                       case 2: base_idx=1; 
+                               break;
+                       case 3: base_idx=1; offset=8;
+                               break;
+                       case 4: /* BAR 2*/
+                       case 5: /* BAR 3 */
+                       case 6: /* BAR 4*/
+                       case 7: base_idx=idx-2; /* BAR 5*/
+               }
+
+       /* Some Titan cards are also a little weird */
+       if (dev->vendor == PCI_VENDOR_ID_TITAN &&
+           (dev->device == PCI_DEVICE_ID_TITAN_400L ||
+            dev->device == PCI_DEVICE_ID_TITAN_800L)) {
+               switch (idx) {
+               case 0: base_idx = 1;
+                       break;
+               case 1: base_idx = 2;
+                       break;
+               default:
+                       base_idx = 4;
+                       offset = 8 * (idx - 2);
+               }
+               
+       }
+  
+       /* HP's Diva chip puts the 4th/5th serial port further out, and
+        * some serial ports are supposed to be hidden on certain models.
+        */
+       if (dev->vendor == PCI_VENDOR_ID_HP &&
+                       dev->device == PCI_DEVICE_ID_HP_SAS) {
+               switch (dev->subsystem_device) {
+               case 0x104B: /* Maestro */
+                       if (idx == 3) idx++;
+                       break;
+               case 0x1282: /* Everest / Longs Peak */
+                       if (idx > 0) idx++;
+                       if (idx > 2) idx++;
+                       break;
+               }
+               if (idx > 2) {
+                       offset = 0x18;
+               }
+       }
+
+       port =  pci_resource_start(dev, base_idx) + offset;
+
+       if ((board->flags & SPCI_FL_BASE_TABLE) == 0)
+               port += idx * (board->uart_offset ? board->uart_offset : 8);
+
+       if (IS_PCI_REGION_IOPORT(dev, base_idx)) {
+               req->port = port;
+               if (HIGH_BITS_OFFSET)
+                       req->port_high = port >> HIGH_BITS_OFFSET;
+               else
+                       req->port_high = 0;
+               return 0;
+       }
+       req->io_type = SERIAL_IO_MEM;
+       req->iomem_base = ioremap(port, board->uart_offset);
+       req->iomem_reg_shift = board->reg_shift;
+       req->port = 0;
+       return 0;
+}
+
+static _INLINE_ int get_pci_irq(struct pci_dev *dev,
+                               struct pci_board *board,
+                               int idx)
+{
+       int base_idx;
+
+       if ((board->flags & SPCI_FL_IRQRESOURCE) == 0)
+               return dev->irq;
+
+       base_idx = SPCI_FL_GET_IRQBASE(board->flags);
+       if (board->flags & SPCI_FL_IRQ_TABLE)
+               base_idx += idx;
+       
+       return PCI_IRQ_RESOURCE(dev, base_idx);
+}
+
+/*
+ * Common enabler code shared by both PCI and ISAPNP probes
+ */
+static void __devinit start_pci_pnp_board(struct pci_dev *dev,
+                                      struct pci_board *board)
+{
+       int k, line;
+       struct serial_struct serial_req;
+       int base_baud;
+
+       if (PREPARE_FUNC(dev) && (PREPARE_FUNC(dev))(dev) < 0) {
+              printk("serial: PNP device '");
+              printk_pnp_dev_id(dev->vendor, dev->device);
+              printk("' prepare failed\n");
+              return;
+       }
+
+       if (ACTIVATE_FUNC(dev) && (ACTIVATE_FUNC(dev))(dev) < 0) {
+              printk("serial: PNP device '");
+              printk_pnp_dev_id(dev->vendor, dev->device);
+              printk("' activate failed\n");
+              return;
+       }
+
+       /*
+        * Run the initialization function, if any
+        */
+       if (board->init_fn && ((board->init_fn)(dev, board, 1) != 0))
+               return;
+
+       /*
+        * Register the serial board in the array if we need to
+        * shutdown the board on a module unload or card removal
+        */
+       if (DEACTIVATE_FUNC(dev) || board->init_fn) {
+               for (k=0; k < NR_PCI_BOARDS; k++)
+                       if (serial_pci_board[k].dev == 0)
+                               break;
+               if (k >= NR_PCI_BOARDS)
+                       return;
+               serial_pci_board[k].board = *board;
+               serial_pci_board[k].dev = dev;
+       }
+
+       base_baud = board->base_baud;
+       if (!base_baud)
+               base_baud = BASE_BAUD;
+       memset(&serial_req, 0, sizeof(serial_req));
+
+       for (k=0; k < board->num_ports; k++) {
+               serial_req.irq = get_pci_irq(dev, board, k);
+               if (get_pci_port(dev, board, &serial_req, k))
+                       break;
+               serial_req.flags = ASYNC_SKIP_TEST | ASYNC_AUTOPROBE;
+#ifdef SERIAL_DEBUG_PCI
+               printk("Setup PCI/PNP port: port %x, irq %d, type %d\n",
+                      serial_req.port, serial_req.irq, serial_req.io_type);
+#endif
+               line = register_serial(&serial_req);
+               if (line < 0)
+                       break;
+               rs_table[line].baud_base = base_baud;
+               rs_table[line].dev = dev;
+       }
+}
+#endif /* ENABLE_SERIAL_PCI || ENABLE_SERIAL_PNP */
+
+#ifdef ENABLE_SERIAL_PCI
+/*
+ * Some PCI serial cards using the PLX 9050 PCI interface chip require
+ * that the card interrupt be explicitly enabled or disabled.  This
+ * seems to be mainly needed on card using the PLX which also use I/O
+ * mapped memory.
+ */
+static int __devinit
+pci_plx9050_fn(struct pci_dev *dev, struct pci_board *board, int enable)
+{
+       u8 data, *p, irq_config;
+       int pci_config;
+
+       irq_config = 0x41;
+       pci_config = PCI_COMMAND_MEMORY;
+       if (dev->vendor == PCI_VENDOR_ID_PANACOM)
+               irq_config = 0x43;
+       if ((dev->vendor == PCI_VENDOR_ID_PLX) &&
+           (dev->device == PCI_DEVICE_ID_PLX_ROMULUS)) {
+               /*
+                * As the megawolf cards have the int pins active
+                * high, and have 2 UART chips, both ints must be
+                * enabled on the 9050. Also, the UARTS are set in
+                * 16450 mode by default, so we have to enable the
+                * 16C950 'enhanced' mode so that we can use the deep
+                * FIFOs
+                */
+               irq_config = 0x5b;
+               pci_config = PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
+       }
+       
+       pci_read_config_byte(dev, PCI_COMMAND, &data);
+
+       if (enable)
+               pci_write_config_byte(dev, PCI_COMMAND,
+                                     data | pci_config);
+       
+       /* enable/disable interrupts */
+       p = ioremap(pci_resource_start(dev, 0), 0x80);
+       writel(enable ? irq_config : 0x00, (unsigned long)p + 0x4c);
+       iounmap(p);
+
+       if (!enable)
+               pci_write_config_byte(dev, PCI_COMMAND,
+                                     data & ~pci_config);
+       return 0;
+}
+
+
+/*
+ * SIIG serial cards have an PCI interface chip which also controls
+ * the UART clocking frequency. Each UART can be clocked independently
+ * (except cards equiped with 4 UARTs) and initial clocking settings
+ * are stored in the EEPROM chip. It can cause problems because this
+ * version of serial driver doesn't support differently clocked UART's
+ * on single PCI card. To prevent this, initialization functions set
+ * high frequency clocking for all UART's on given card. It is safe (I
+ * hope) because it doesn't touch EEPROM settings to prevent conflicts
+ * with other OSes (like M$ DOS).
+ *
+ *  SIIG support added by Andrey Panin <pazke@mail.tp.ru>, 10/1999
+ * 
+ * There is two family of SIIG serial cards with different PCI
+ * interface chip and different configuration methods:
+ *     - 10x cards have control registers in IO and/or memory space;
+ *     - 20x cards have control registers in standard PCI configuration space.
+ *
+ * SIIG initialization functions exported for use by parport_serial.c module.
+ */
+
+#define PCI_DEVICE_ID_SIIG_1S_10x (PCI_DEVICE_ID_SIIG_1S_10x_550 & 0xfffc)
+#define PCI_DEVICE_ID_SIIG_2S_10x (PCI_DEVICE_ID_SIIG_2S_10x_550 & 0xfff8)
+
+int __devinit
+pci_siig10x_fn(struct pci_dev *dev, struct pci_board *board, int enable)
+{
+       u16 data, *p;
+
+       if (!enable) return 0;
+
+       p = ioremap(pci_resource_start(dev, 0), 0x80);
+
+       switch (dev->device & 0xfff8) {
+               case PCI_DEVICE_ID_SIIG_1S_10x:         /* 1S */
+                       data = 0xffdf;
+                       break;
+               case PCI_DEVICE_ID_SIIG_2S_10x:         /* 2S, 2S1P */
+                       data = 0xf7ff;
+                       break;
+               default:                                /* 1S1P, 4S */
+                       data = 0xfffb;
+                       break;
+       }
+
+       writew(readw((unsigned long) p + 0x28) & data, (unsigned long) p + 
0x28);
+       iounmap(p);
+       return 0;
+}
+EXPORT_SYMBOL(pci_siig10x_fn);
+
+#define PCI_DEVICE_ID_SIIG_2S_20x (PCI_DEVICE_ID_SIIG_2S_20x_550 & 0xfffc)
+#define PCI_DEVICE_ID_SIIG_2S1P_20x (PCI_DEVICE_ID_SIIG_2S1P_20x_550 & 0xfffc)
+
+int __devinit
+pci_siig20x_fn(struct pci_dev *dev, struct pci_board *board, int enable)
+{
+       u8 data;
+
+       if (!enable) return 0;
+
+       /* Change clock frequency for the first UART. */
+       pci_read_config_byte(dev, 0x6f, &data);
+       pci_write_config_byte(dev, 0x6f, data & 0xef);
+
+       /* If this card has 2 UART, we have to do the same with second UART. */
+       if (((dev->device & 0xfffc) == PCI_DEVICE_ID_SIIG_2S_20x) ||
+           ((dev->device & 0xfffc) == PCI_DEVICE_ID_SIIG_2S1P_20x)) {
+               pci_read_config_byte(dev, 0x73, &data);
+               pci_write_config_byte(dev, 0x73, data & 0xef);
+       }
+       return 0;
+}
+EXPORT_SYMBOL(pci_siig20x_fn);
+
+/* Added for EKF Intel i960 serial boards */
+static int __devinit
+pci_inteli960ni_fn(struct pci_dev *dev,
+                  struct pci_board *board,
+                  int enable)
+{
+       unsigned long oldval;
+       
+       if (!(pci_get_subdevice(dev) & 0x1000))
+               return(-1);
+
+       if (!enable) /* is there something to deinit? */
+               return(0);
+   
+#ifdef SERIAL_DEBUG_PCI
+       printk(KERN_DEBUG " Subsystem ID %lx (intel 960)\n",
+              (unsigned long) board->subdevice);
+#endif
+       /* is firmware started? */
+       pci_read_config_dword(dev, 0x44, (void*) &oldval); 
+       if (oldval == 0x00001000L) { /* RESET value */ 
+               printk(KERN_DEBUG "Local i960 firmware missing");
+               return(-1); 
+       }
+       return(0);
+}
+
+/*
+ * Timedia has an explosion of boards, and to avoid the PCI table from
+ * growing *huge*, we use this function to collapse some 70 entries
+ * in the PCI table into one, for sanity's and compactness's sake.
+ */
+static unsigned short timedia_single_port[] = {
+       0x4025, 0x4027, 0x4028, 0x5025, 0x5027, 0 };
+static unsigned short timedia_dual_port[] = {
+       0x0002, 0x4036, 0x4037, 0x4038, 0x4078, 0x4079, 0x4085,
+       0x4088, 0x4089, 0x5037, 0x5078, 0x5079, 0x5085, 0x6079, 
+       0x7079, 0x8079, 0x8137, 0x8138, 0x8237, 0x8238, 0x9079, 
+       0x9137, 0x9138, 0x9237, 0x9238, 0xA079, 0xB079, 0xC079,
+       0xD079, 0 };
+static unsigned short timedia_quad_port[] = {
+       0x4055, 0x4056, 0x4095, 0x4096, 0x5056, 0x8156, 0x8157, 
+       0x8256, 0x8257, 0x9056, 0x9156, 0x9157, 0x9158, 0x9159, 
+       0x9256, 0x9257, 0xA056, 0xA157, 0xA158, 0xA159, 0xB056,
+       0xB157, 0 };
+static unsigned short timedia_eight_port[] = {
+       0x4065, 0x4066, 0x5065, 0x5066, 0x8166, 0x9066, 0x9166, 
+       0x9167, 0x9168, 0xA066, 0xA167, 0xA168, 0 };
+static struct timedia_struct {
+       int num;
+       unsigned short *ids;
+} timedia_data[] = {
+       { 1, timedia_single_port },
+       { 2, timedia_dual_port },
+       { 4, timedia_quad_port },
+       { 8, timedia_eight_port },
+       { 0, 0 }
+};
+
+static int __devinit
+pci_timedia_fn(struct pci_dev *dev, struct pci_board *board, int enable)
+{
+       int     i, j;
+       unsigned short *ids;
+
+       if (!enable)
+               return 0;
+
+       for (i=0; timedia_data[i].num; i++) {
+               ids = timedia_data[i].ids;
+               for (j=0; ids[j]; j++) {
+                       if (pci_get_subdevice(dev) == ids[j]) {
+                               board->num_ports = timedia_data[i].num;
+                               return 0;
+                       }
+               }
+       }
+       return 0;
+}
+
+/*
+ * HP's Remote Management Console.  The Diva chip came in several
+ * different versions.  N-class, L2000 and A500 have two Diva chips, each
+ * with 3 UARTs (the third UART on the second chip is unused).  Superdome
+ * and Keystone have one Diva chip with 3 UARTs.  Some later machines have
+ * one Diva chip, but it has been expanded to 5 UARTs.
+ */
+static int __devinit
+pci_hp_diva(struct pci_dev *dev, struct pci_board *board, int enable)
+{
+       if (!enable)
+               return 0;
+
+       switch (dev->subsystem_device) {
+       case 0x1049: /* Prelude Diva 1 */
+       case 0x1223: /* Superdome */
+       case 0x1226: /* Keystone */
+       case 0x1282: /* Everest / Longs Peak */
+               board->num_ports = 3;
+               break;
+       case 0x104A: /* Prelude Diva 2 */
+               board->num_ports = 2;
+               break;
+       case 0x104B: /* Maestro */
+               board->num_ports = 4;
+               break;
+       case 0x1227: /* Powerbar */
+               board->num_ports = 1;
+               break;
+       }
+
+       return 0;
+}
+
+static int __devinit
+pci_xircom_fn(struct pci_dev *dev, struct pci_board *board, int enable)
+{
+       __set_current_state(TASK_UNINTERRUPTIBLE);
+       schedule_timeout(HZ/10);
+       return 0;
+}
+
+/*
+ * This is the configuration table for all of the PCI serial boards
+ * which we support.  It is directly indexed by the pci_board_num_t enum
+ * value, which is encoded in the pci_device_id PCI probe table's
+ * driver_data member.
+ */
+enum pci_board_num_t {
+       pbn_b0_1_115200,
+       pbn_default = 0,
+
+       pbn_b0_2_115200,
+       pbn_b0_4_115200,
+
+       pbn_b0_1_921600,
+       pbn_b0_2_921600,
+       pbn_b0_4_921600,
+
+       pbn_b0_bt_1_115200,
+       pbn_b0_bt_2_115200,
+       pbn_b0_bt_1_460800,
+       pbn_b0_bt_2_460800,
+       pbn_b0_bt_2_921600,
+
+       pbn_b1_1_115200,
+       pbn_b1_2_115200,
+       pbn_b1_4_115200,
+       pbn_b1_8_115200,
+
+       pbn_b1_2_921600,
+       pbn_b1_4_921600,
+       pbn_b1_8_921600,
+
+       pbn_b1_2_1382400,
+       pbn_b1_4_1382400,
+       pbn_b1_8_1382400,
+
+       pbn_b2_1_115200,
+       pbn_b2_8_115200,
+       pbn_b2_4_460800,
+       pbn_b2_8_460800,
+       pbn_b2_16_460800,
+       pbn_b2_4_921600,
+       pbn_b2_8_921600,
+
+       pbn_b2_bt_1_115200,
+       pbn_b2_bt_2_115200,
+       pbn_b2_bt_4_115200,
+       pbn_b2_bt_2_921600,
+
+       pbn_panacom,
+       pbn_panacom2,
+       pbn_panacom4,
+       pbn_plx_romulus,
+       pbn_oxsemi,
+       pbn_timedia,
+       pbn_intel_i960,
+       pbn_sgi_ioc3,
+       pbn_hp_diva,
+#ifdef CONFIG_DDB5074
+       pbn_nec_nile4,
+#endif
+
+       pbn_dci_pccom4,
+       pbn_dci_pccom8,
+
+       pbn_xircom_combo,
+
+       pbn_siig10x_0,
+       pbn_siig10x_1,
+       pbn_siig10x_2,
+       pbn_siig10x_4,
+       pbn_siig20x_0,
+       pbn_siig20x_2,
+       pbn_siig20x_4,
+       
+       pbn_computone_4,
+       pbn_computone_6,
+       pbn_computone_8,
+};
+
+static struct pci_board pci_boards[] __devinitdata = {
+       /*
+        * PCI Flags, Number of Ports, Base (Maximum) Baud Rate,
+        * Offset to get to next UART's registers,
+        * Register shift to use for memory-mapped I/O,
+        * Initialization function, first UART offset
+        */
+
+       /* Generic serial board, pbn_b0_1_115200, pbn_default */
+       { SPCI_FL_BASE0, 1, 115200 },           /* pbn_b0_1_115200,
+                                                  pbn_default */
+
+       { SPCI_FL_BASE0, 2, 115200 },           /* pbn_b0_2_115200 */
+       { SPCI_FL_BASE0, 4, 115200 },           /* pbn_b0_4_115200 */
+
+       { SPCI_FL_BASE0, 1, 921600 },           /* pbn_b0_1_921600 */
+       { SPCI_FL_BASE0, 2, 921600 },           /* pbn_b0_2_921600 */
+       { SPCI_FL_BASE0, 4, 921600 },           /* pbn_b0_4_921600 */
+
+       { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 }, /* 
pbn_b0_bt_1_115200 */
+       { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, /* 
pbn_b0_bt_2_115200 */
+       { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 460800 }, /* 
pbn_b0_bt_1_460800 */
+       { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 460800 }, /* 
pbn_b0_bt_2_460800 */
+       { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600 }, /* 
pbn_b0_bt_2_921600 */
+
+       { SPCI_FL_BASE1, 1, 115200 },           /* pbn_b1_1_115200 */
+       { SPCI_FL_BASE1, 2, 115200 },           /* pbn_b1_2_115200 */
+       { SPCI_FL_BASE1, 4, 115200 },           /* pbn_b1_4_115200 */
+       { SPCI_FL_BASE1, 8, 115200 },           /* pbn_b1_8_115200 */
+
+       { SPCI_FL_BASE1, 2, 921600 },           /* pbn_b1_2_921600 */
+       { SPCI_FL_BASE1, 4, 921600 },           /* pbn_b1_4_921600 */
+       { SPCI_FL_BASE1, 8, 921600 },           /* pbn_b1_8_921600 */
+
+       { SPCI_FL_BASE1, 2, 1382400 },          /* pbn_b1_2_1382400 */
+       { SPCI_FL_BASE1, 4, 1382400 },          /* pbn_b1_4_1382400 */
+       { SPCI_FL_BASE1, 8, 1382400 },          /* pbn_b1_8_1382400 */
+
+       { SPCI_FL_BASE2, 1, 115200 },           /* pbn_b2_1_115200 */
+       { SPCI_FL_BASE2, 8, 115200 },           /* pbn_b2_8_115200 */
+       { SPCI_FL_BASE2, 4, 460800 },           /* pbn_b2_4_460800 */
+       { SPCI_FL_BASE2, 8, 460800 },           /* pbn_b2_8_460800 */
+       { SPCI_FL_BASE2, 16, 460800 },          /* pbn_b2_16_460800 */
+       { SPCI_FL_BASE2, 4, 921600 },           /* pbn_b2_4_921600 */
+       { SPCI_FL_BASE2, 8, 921600 },           /* pbn_b2_8_921600 */
+
+       { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 1, 115200 }, /* 
pbn_b2_bt_1_115200 */
+       { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 }, /* 
pbn_b2_bt_2_115200 */
+       { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 115200 }, /* 
pbn_b2_bt_4_115200 */
+       { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600 }, /* 
pbn_b2_bt_2_921600 */
+
+       { SPCI_FL_BASE2, 2, 921600, /* IOMEM */            /* pbn_panacom */
+               0x400, 7, pci_plx9050_fn },
+       { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600,   /* pbn_panacom2 */
+               0x400, 7, pci_plx9050_fn },
+       { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600,   /* pbn_panacom4 */
+               0x400, 7, pci_plx9050_fn },
+       { SPCI_FL_BASE2, 4, 921600,                        /* pbn_plx_romulus */
+               0x20, 2, pci_plx9050_fn, 0x03 },
+               /* This board uses the size of PCI Base region 0 to
+                * signal now many ports are available */
+       { SPCI_FL_BASE0 | SPCI_FL_REGION_SZ_CAP, 32, 115200 }, /* pbn_oxsemi */
+       { SPCI_FL_BASE_TABLE, 1, 921600,                   /* pbn_timedia */
+               0, 0, pci_timedia_fn },
+       /* EKF addition for i960 Boards form EKF with serial port */
+       { SPCI_FL_BASE0, 32, 921600, /* max 256 ports */   /* pbn_intel_i960 */
+               8<<2, 2, pci_inteli960ni_fn, 0x10000},
+       { SPCI_FL_BASE0 | SPCI_FL_IRQRESOURCE,             /* pbn_sgi_ioc3 */
+               1, 458333, 0, 0, 0, 0x20178 },
+       { SPCI_FL_BASE0, 5, 115200, 8, 0, pci_hp_diva, 0},   /* pbn_hp_diva */
+#ifdef CONFIG_DDB5074
+       /*
+        * NEC Vrc-5074 (Nile 4) builtin UART.
+        * Conditionally compiled in since this is a motherboard device.
+        */
+       { SPCI_FL_BASE0, 1, 520833,                        /* pbn_nec_nile4 */
+               64, 3, NULL, 0x300 },
+#endif
+
+       {SPCI_FL_BASE3, 4, 115200, 8},                     /* pbn_dci_pccom4 */
+       {SPCI_FL_BASE3, 8, 115200, 8},                     /* pbn_dci_pccom8 */
+
+       { SPCI_FL_BASE0, 1, 115200,                       /* pbn_xircom_combo */
+               0, 0, pci_xircom_fn },
+
+       { SPCI_FL_BASE2, 1, 460800,                        /* pbn_siig10x_0 */
+               0, 0, pci_siig10x_fn },
+       { SPCI_FL_BASE2, 1, 921600,                        /* pbn_siig10x_1 */
+               0, 0, pci_siig10x_fn },
+       { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600,   /* pbn_siig10x_2 */
+               0, 0, pci_siig10x_fn },
+       { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600,   /* pbn_siig10x_4 */
+               0, 0, pci_siig10x_fn },
+       { SPCI_FL_BASE0, 1, 921600,                        /* pbn_siix20x_0 */
+               0, 0, pci_siig20x_fn },
+       { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600,   /* pbn_siix20x_2 */
+               0, 0, pci_siig20x_fn },
+       { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 921600,   /* pbn_siix20x_4 */
+               0, 0, pci_siig20x_fn },
+
+       { SPCI_FL_BASE0, 4, 921600, /* IOMEM */            /* pbn_computone_4 */
+               0x40, 2, NULL, 0x200 },
+       { SPCI_FL_BASE0, 6, 921600, /* IOMEM */            /* pbn_computone_6 */
+               0x40, 2, NULL, 0x200 },
+       { SPCI_FL_BASE0, 8, 921600, /* IOMEM */            /* pbn_computone_8 */
+               0x40, 2, NULL, 0x200 },
+};
+
+/*
+ * Given a complete unknown PCI device, try to use some heuristics to
+ * guess what the configuration might be, based on the pitiful PCI
+ * serial specs.  Returns 0 on success, 1 on failure.
+ */
+static int __devinit serial_pci_guess_board(struct pci_dev *dev,
+                                          struct pci_board *board)
+{
+       int     num_iomem = 0, num_port = 0, first_port = -1;
+       int     i;
+       
+       /*
+        * If it is not a communications device or the programming
+        * interface is greater than 6, give up.
+        *
+        * (Should we try to make guesses for multiport serial devices
+        * later?) 
+        */
+       if ((((dev->class >> 8) != PCI_CLASS_COMMUNICATION_SERIAL) &&
+           ((dev->class >> 8) != PCI_CLASS_COMMUNICATION_MODEM)) ||
+           (dev->class & 0xff) > 6)
+               return 1;
+
+       for (i=0; i < 6; i++) {
+               if (IS_PCI_REGION_IOPORT(dev, i)) {
+                       num_port++;
+                       if (first_port == -1)
+                               first_port = i;
+               }
+               if (IS_PCI_REGION_IOMEM(dev, i))
+                       num_iomem++;
+       }
+
+       /*
+        * If there is 1 or 0 iomem regions, and exactly one port, use
+        * it.
+        */
+       if (num_iomem <= 1 && num_port == 1) {
+               board->flags = first_port;
+               return 0;
+       }
+       return 1;
+}
+
+static int __devinit serial_init_one(struct pci_dev *dev,
+                                    const struct pci_device_id *ent)
+{
+       struct pci_board *board, tmp;
+       int rc;
+
+       board = &pci_boards[ent->driver_data];
+
+       rc = pci_enable_device(dev);
+       if (rc) return rc;
+
+       if (ent->driver_data == pbn_default &&
+           serial_pci_guess_board(dev, board))
+               return -ENODEV;
+       else if (serial_pci_guess_board(dev, &tmp) == 0) {
+               printk(KERN_INFO "Redundant entry in serial pci_table.  "
+                      "Please send the output of\n"
+                      "lspci -vv, this message (%04x,%04x,%04x,%04x)\n"
+                      "and the manufacturer and name of "
+                      "serial board or modem board\n"
+                      "to serial-pci-info@lists.sourceforge.net.\n",
+                      dev->vendor, dev->device,
+                      pci_get_subvendor(dev), pci_get_subdevice(dev));
+       }
+                      
+       start_pci_pnp_board(dev, board);
+
+       return 0;
+}
+
+static void __devexit serial_remove_one(struct pci_dev *dev)
+{
+       int     i;
+
+       /*
+        * Iterate through all of the ports finding those that belong
+        * to this PCI device.
+        */
+       for(i = 0; i < NR_PORTS; i++) {
+               if (rs_table[i].dev != dev)
+                       continue;
+               unregister_serial(i);
+               rs_table[i].dev = 0;
+       }
+       /*
+        * Now execute any board-specific shutdown procedure
+        */
+       for (i=0; i < NR_PCI_BOARDS; i++) {
+               struct pci_board_inst *brd = &serial_pci_board[i];
+
+               if (serial_pci_board[i].dev != dev)
+                       continue;
+               if (brd->board.init_fn)
+                       (brd->board.init_fn)(brd->dev, &brd->board, 0);
+               if (DEACTIVATE_FUNC(brd->dev))
+                       (DEACTIVATE_FUNC(brd->dev))(brd->dev);
+               serial_pci_board[i].dev = 0;
+       }
+}
+
+
+static struct pci_device_id serial_pci_tbl[] __devinitdata = {
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0,
+               pbn_b1_8_1382400 },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, 0, 0,
+               pbn_b1_4_1382400 },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, 0, 0,
+               pbn_b1_2_1382400 },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0,
+               pbn_b1_8_1382400 },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, 0, 0,
+               pbn_b1_4_1382400 },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, 0, 0,
+               pbn_b1_2_1382400 },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485, 0, 0,
+               pbn_b1_8_921600 },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4, 0, 0,
+               pbn_b1_8_921600 },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485, 0, 0,
+               pbn_b1_4_921600 },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2, 0, 0,
+               pbn_b1_4_921600 },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485, 0, 0,
+               pbn_b1_2_921600 },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_2_6, 0, 0,
+               pbn_b1_8_921600 },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH081101V1, 0, 0,
+               pbn_b1_8_921600 },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH041101V1, 0, 0,
+               pbn_b1_4_921600 },
+
+       {       PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_U530,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+               pbn_b2_bt_1_115200 },
+       {       PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM2,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+               pbn_b2_bt_2_115200 },
+       {       PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM422,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+               pbn_b2_bt_4_115200 },
+       {       PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM232,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+               pbn_b2_bt_2_115200 },
+       {       PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM4,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+               pbn_b2_bt_4_115200 },
+       {       PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM8,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+               pbn_b2_8_115200 },
+
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_GTEK_SERIAL2,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_bt_2_115200 },
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM200,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_bt_2_921600 },
+       /* VScom SPCOM800, from sl@s.pl */
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM800, 
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+               pbn_b2_8_921600 },
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_1077,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+               pbn_b2_4_921600 },
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+               PCI_SUBVENDOR_ID_KEYSPAN,
+               PCI_SUBDEVICE_ID_KEYSPAN_SX2, 0, 0,
+               pbn_panacom },
+       {       PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_QUADMODEM,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_panacom4 },
+       {       PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_DUALMODEM,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_panacom2 },
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+               PCI_SUBVENDOR_ID_CHASE_PCIFAST,
+               PCI_SUBDEVICE_ID_CHASE_PCIFAST4, 0, 0, 
+               pbn_b2_4_460800 },
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+               PCI_SUBVENDOR_ID_CHASE_PCIFAST,
+               PCI_SUBDEVICE_ID_CHASE_PCIFAST8, 0, 0, 
+               pbn_b2_8_460800 },
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+               PCI_SUBVENDOR_ID_CHASE_PCIFAST,
+               PCI_SUBDEVICE_ID_CHASE_PCIFAST16, 0, 0, 
+               pbn_b2_16_460800 },
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+               PCI_SUBVENDOR_ID_CHASE_PCIFAST,
+               PCI_SUBDEVICE_ID_CHASE_PCIFAST16FMC, 0, 0, 
+               pbn_b2_16_460800 },
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+               PCI_SUBVENDOR_ID_CHASE_PCIRAS,
+               PCI_SUBDEVICE_ID_CHASE_PCIRAS4, 0, 0, 
+               pbn_b2_4_460800 },
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+               PCI_SUBVENDOR_ID_CHASE_PCIRAS,
+               PCI_SUBDEVICE_ID_CHASE_PCIRAS8, 0, 0, 
+               pbn_b2_8_460800 },
+       /* Megawolf Romulus PCI Serial Card, from Mike Hudson */
+       /* (Exoray@isys.ca) */
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_ROMULUS,
+               0x10b5, 0x106a, 0, 0,
+               pbn_plx_romulus },
+       {       PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSC100,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+               pbn_b1_4_115200 },
+       {       PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC100,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+               pbn_b1_2_115200 },
+       {       PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100D,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+               pbn_b1_8_115200 },
+       {       PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100M,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+               pbn_b1_8_115200 },
+       {       PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_OXSEMI_16PCI954,
+               PCI_VENDOR_ID_SPECIALIX, PCI_SUBDEVICE_ID_SPECIALIX_SPEED4, 0, 
0, 
+               pbn_b0_4_921600 },
+       {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+               pbn_b0_4_115200 },
+       {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI952,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+               pbn_b0_bt_2_921600 },
+
+       /* Digitan DS560-558, from jimd@esoft.com */
+       {       PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_ATT_VENUS_MODEM,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+               pbn_b1_1_115200 },
+
+       /* 3Com US Robotics 56k Voice Internal PCI model 5610 */
+       {       PCI_VENDOR_ID_USR, 0x1008,
+               PCI_ANY_ID, PCI_ANY_ID, },
+
+       /* Titan Electronic cards */
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+               pbn_b0_1_921600 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+               pbn_b0_2_921600 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+               pbn_b0_4_921600 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800B,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+               pbn_b0_4_921600 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100L,
+               PCI_ANY_ID, PCI_ANY_ID,
+               SPCI_FL_BASE1, 1, 921600 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200L,
+               PCI_ANY_ID, PCI_ANY_ID,
+               SPCI_FL_BASE1 | SPCI_FL_BASE_TABLE, 2, 921600 },
+       /* The 400L and 800L have a custom hack in get_pci_port */
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400L,
+               PCI_ANY_ID, PCI_ANY_ID,
+               SPCI_FL_BASE_TABLE, 4, 921600 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800L,
+               PCI_ANY_ID, PCI_ANY_ID,
+               SPCI_FL_BASE_TABLE, 8, 921600 },
+
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_550,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig10x_0 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_650,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig10x_0 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_850,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig10x_0 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_550,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig10x_2 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_650,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig10x_2 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_850,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig10x_2 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_550,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig10x_4 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_650,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig10x_4 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_850,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig10x_4 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_550,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig20x_0 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_650,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig20x_0 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_850,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig20x_0 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_550,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig20x_2 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_650,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig20x_2 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_850,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig20x_2 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_550,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig20x_4 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_650,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig20x_4 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_850,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig20x_4 },
+
+       /* Computone devices submitted by Doug McNash dmcnash@computone.com */
+       {       PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
+               PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG4,
+               0, 0, pbn_computone_4 },
+       {       PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
+               PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG8,
+               0, 0, pbn_computone_8 },
+       {       PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
+               PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG6,
+               0, 0, pbn_computone_6 },
+
+       {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI95N,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_oxsemi },
+       {       PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_1889,
+               PCI_VENDOR_ID_TIMEDIA, PCI_ANY_ID, 0, 0, pbn_timedia },
+
+       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DSERIAL,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_2_115200 },
+       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_A,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_2_115200 },
+       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_B,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_2_115200 },
+       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_PLUS,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_2_460800 },
+       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_A,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_2_460800 },
+       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_B,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_2_460800 },
+       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_SSERIAL,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_1_115200 },
+       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_650,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_1_460800 },
+
+       /* RAStel 2 port modem, gerg@moreton.com.au */
+       {       PCI_VENDOR_ID_MORETON, PCI_DEVICE_ID_RASTEL_2PORT,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_bt_2_115200 },
+
+       /* EKF addition for i960 Boards form EKF with serial port */
+       {       PCI_VENDOR_ID_INTEL, 0x1960,
+               0xE4BF, PCI_ANY_ID, 0, 0,
+               pbn_intel_i960 },
+
+       /* Xircom Cardbus/Ethernet combos */
+       {       PCI_VENDOR_ID_XIRCOM, PCI_DEVICE_ID_XIRCOM_X3201_MDM,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_xircom_combo },
+
+       /*
+        * Untested PCI modems, sent in from various folks...
+        */
+
+       /* Elsa Model 56K PCI Modem, from Andreas Rath <arh@01019freenet.de> */
+       {       PCI_VENDOR_ID_ROCKWELL, 0x1004,
+               0x1048, 0x1500, 0, 0,
+               pbn_b1_1_115200 },
+
+       {       PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3,
+               0xFF00, 0, 0, 0,
+               pbn_sgi_ioc3 },
+
+       /* HP Diva card */
+       {       PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_SAS,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_hp_diva },
+       {       PCI_VENDOR_ID_HP, 0x1290,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_1_115200 },
+
+#ifdef CONFIG_DDB5074
+       /*
+        * NEC Vrc-5074 (Nile 4) builtin UART.
+        * Conditionally compiled in since this is a motherboard device.
+        */
+       {       PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_NILE4,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_nec_nile4 },
+#endif
+
+       {       PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM4,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_dci_pccom4 },
+       {       PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM8,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_dci_pccom8 },
+
+       { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+        PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xffff00, },
+       { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+        PCI_CLASS_COMMUNICATION_MODEM << 8, 0xffff00, },
+       { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, serial_pci_tbl);
+
+static struct pci_driver serial_pci_driver = {
+       name:           "serial",
+       probe:          serial_init_one,
+       remove:        __devexit_p(serial_remove_one),
+       id_table:       serial_pci_tbl,
+};
+
+
+/*
+ * Query PCI space for known serial boards
+ * If found, add them to the PCI device space in rs_table[]
+ *
+ * Accept a maximum of eight boards
+ *
+ */
+static void __devinit probe_serial_pci(void) 
+{
+#ifdef SERIAL_DEBUG_PCI
+       printk(KERN_DEBUG "Entered probe_serial_pci()\n");
+#endif
+
+       /* Register call PCI serial devices.  Null out
+        * the driver name upon failure, as a signal
+        * not to attempt to unregister the driver later
+        */
+       if (pci_module_init (&serial_pci_driver) != 0)
+               serial_pci_driver.name = "";
+
+#ifdef SERIAL_DEBUG_PCI
+       printk(KERN_DEBUG "Leaving probe_serial_pci() (probe finished)\n");
+#endif
+       return;
+}
+
+#endif /* ENABLE_SERIAL_PCI */
+
+#ifdef ENABLE_SERIAL_PNP
+
+struct pnp_board {
+       unsigned short vendor;
+       unsigned short device;
+};
+
+static struct pnp_board pnp_devices[] __devinitdata = {
+       /* Archtek America Corp. */
+       /* Archtek SmartLink Modem 3334BT Plug & Play */
+       {       ISAPNP_VENDOR('A', 'A', 'C'), ISAPNP_DEVICE(0x000F) },
+       /* Anchor Datacomm BV */
+       /* SXPro 144 External Data Fax Modem Plug & Play */
+       {       ISAPNP_VENDOR('A', 'D', 'C'), ISAPNP_DEVICE(0x0001) },
+       /* SXPro 288 External Data Fax Modem Plug & Play */
+       {       ISAPNP_VENDOR('A', 'D', 'C'), ISAPNP_DEVICE(0x0002) },
+       /* Rockwell 56K ACF II Fax+Data+Voice Modem */
+       {       ISAPNP_VENDOR('A', 'K', 'Y'), ISAPNP_DEVICE(0x1021) },
+       /* AZT3005 PnP SOUND DEVICE */
+       {       ISAPNP_VENDOR('A', 'Z', 'T'), ISAPNP_DEVICE(0x4001) },
+       /* Best Data Products Inc. Smart One 336F PnP Modem */
+       {       ISAPNP_VENDOR('B', 'D', 'P'), ISAPNP_DEVICE(0x3336) },
+       /*  Boca Research */
+       /* Boca Complete Ofc Communicator 14.4 Data-FAX */
+       {       ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x0A49) },
+       /* Boca Research 33,600 ACF Modem */
+       {       ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x1400) },
+       /* Boca 33.6 Kbps Internal FD34FSVD */
+       {       ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x3400) },
+       /* Boca 33.6 Kbps Internal FD34FSVD */
+       {       ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x0A49) },
+       /* Best Data Products Inc. Smart One 336F PnP Modem */
+       {       ISAPNP_VENDOR('B', 'D', 'P'), ISAPNP_DEVICE(0x3336) },
+       /* Computer Peripherals Inc */
+       /* EuroViVa CommCenter-33.6 SP PnP */
+       {       ISAPNP_VENDOR('C', 'P', 'I'), ISAPNP_DEVICE(0x4050) },
+       /* Creative Labs */
+       /* Creative Labs Phone Blaster 28.8 DSVD PnP Voice */
+       {       ISAPNP_VENDOR('C', 'T', 'L'), ISAPNP_DEVICE(0x3001) },
+       /* Creative Labs Modem Blaster 28.8 DSVD PnP Voice */
+       {       ISAPNP_VENDOR('C', 'T', 'L'), ISAPNP_DEVICE(0x3011) },
+       /* Creative */
+       /* Creative Modem Blaster Flash56 DI5601-1 */
+       {       ISAPNP_VENDOR('D', 'M', 'B'), ISAPNP_DEVICE(0x1032) },
+       /* Creative Modem Blaster V.90 DI5660 */
+       {       ISAPNP_VENDOR('D', 'M', 'B'), ISAPNP_DEVICE(0x2001) },
+       /* FUJITSU */
+       /* Fujitsu 33600 PnP-I2 R Plug & Play */
+       {       ISAPNP_VENDOR('F', 'U', 'J'), ISAPNP_DEVICE(0x0202) },
+       /* Fujitsu FMV-FX431 Plug & Play */
+       {       ISAPNP_VENDOR('F', 'U', 'J'), ISAPNP_DEVICE(0x0205) },
+       /* Fujitsu 33600 PnP-I4 R Plug & Play */
+       {       ISAPNP_VENDOR('F', 'U', 'J'), ISAPNP_DEVICE(0x0206) },
+       /* Fujitsu Fax Voice 33600 PNP-I5 R Plug & Play */
+       {       ISAPNP_VENDOR('F', 'U', 'J'), ISAPNP_DEVICE(0x0209) },
+       /* Archtek America Corp. */
+       /* Archtek SmartLink Modem 3334BT Plug & Play */
+       {       ISAPNP_VENDOR('G', 'V', 'C'), ISAPNP_DEVICE(0x000F) },
+       /* Hayes */
+       /* Hayes Optima 288 V.34-V.FC + FAX + Voice Plug & Play */
+       {       ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x0001) },
+       /* Hayes Optima 336 V.34 + FAX + Voice PnP */
+       {       ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x000C) },
+       /* Hayes Optima 336B V.34 + FAX + Voice PnP */
+       {       ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x000D) },
+       /* Hayes Accura 56K Ext Fax Modem PnP */
+       {       ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x5670) },
+       /* Hayes Accura 56K Ext Fax Modem PnP */
+       {       ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x5674) },
+       /* Hayes Accura 56K Fax Modem PnP */
+       {       ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x5675) },
+       /* Hayes 288, V.34 + FAX */
+       {       ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0xF000) },
+       /* Hayes Optima 288 V.34 + FAX + Voice, Plug & Play */
+       {       ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0xF001) },
+       /* IBM */
+       /* IBM Thinkpad 701 Internal Modem Voice */
+       {       ISAPNP_VENDOR('I', 'B', 'M'), ISAPNP_DEVICE(0x0033) },
+       /* Intertex */
+       /* Intertex 28k8 33k6 Voice EXT PnP */
+       {       ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xC801) },
+       /* Intertex 33k6 56k Voice EXT PnP */
+       {       ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xC901) },
+       /* Intertex 28k8 33k6 Voice SP EXT PnP */
+       {       ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xD801) },
+       /* Intertex 33k6 56k Voice SP EXT PnP */
+       {       ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xD901) },
+       /* Intertex 28k8 33k6 Voice SP INT PnP */
+       {       ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xF401) },
+       /* Intertex 28k8 33k6 Voice SP EXT PnP */
+       {       ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xF801) },
+       /* Intertex 33k6 56k Voice SP EXT PnP */
+       {       ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xF901) },
+       /* Kortex International */
+       /* KORTEX 28800 Externe PnP */
+       {       ISAPNP_VENDOR('K', 'O', 'R'), ISAPNP_DEVICE(0x4522) },
+       /* KXPro 33.6 Vocal ASVD PnP */
+       {       ISAPNP_VENDOR('K', 'O', 'R'), ISAPNP_DEVICE(0xF661) },
+       /* Lasat */
+       /* LASAT Internet 33600 PnP */
+       {       ISAPNP_VENDOR('L', 'A', 'S'), ISAPNP_DEVICE(0x4040) },
+       /* Lasat Safire 560 PnP */
+       {       ISAPNP_VENDOR('L', 'A', 'S'), ISAPNP_DEVICE(0x4540) },
+       /* Lasat Safire 336  PnP */
+       {       ISAPNP_VENDOR('L', 'A', 'S'), ISAPNP_DEVICE(0x5440) },
+       /* Microcom, Inc. */
+       /* Microcom TravelPorte FAST V.34 Plug & Play */
+       {       ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x281) },
+       /* Microcom DeskPorte V.34 FAST or FAST+ Plug & Play */
+       {       ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0336) },
+       /* Microcom DeskPorte FAST EP 28.8 Plug & Play */
+       {       ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0339) },
+       /* Microcom DeskPorte 28.8P Plug & Play */
+       {       ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0342) },
+       /* Microcom DeskPorte FAST ES 28.8 Plug & Play */
+       {       ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0500) },
+       /* Microcom DeskPorte FAST ES 28.8 Plug & Play */
+       {       ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0501) },
+       /* Microcom DeskPorte 28.8S Internal Plug & Play */
+       {       ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0502) },
+       /* Motorola */
+       /* Motorola BitSURFR Plug & Play */
+       {       ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1105) },
+       /* Motorola TA210 Plug & Play */
+       {       ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1111) },
+       /* Motorola HMTA 200 (ISDN) Plug & Play */
+       {       ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1114) },
+       /* Motorola BitSURFR Plug & Play */
+       {       ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1115) },
+       /* Motorola Lifestyle 28.8 Internal */
+       {       ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1190) },
+       /* Motorola V.3400 Plug & Play */
+       {       ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1501) },
+       /* Motorola Lifestyle 28.8 V.34 Plug & Play */
+       {       ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1502) },
+       /* Motorola Power 28.8 V.34 Plug & Play */
+       {       ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1505) },
+       /* Motorola ModemSURFR External 28.8 Plug & Play */
+       {       ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1509) },
+       /* Motorola Premier 33.6 Desktop Plug & Play */
+       {       ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x150A) },
+       /* Motorola VoiceSURFR 56K External PnP */
+       {       ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x150F) },
+       /* Motorola ModemSURFR 56K External PnP */
+       {       ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1510) },
+       /* Motorola ModemSURFR 56K Internal PnP */
+       {       ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1550) },
+       /* Motorola ModemSURFR Internal 28.8 Plug & Play */
+       {       ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1560) },
+       /* Motorola Premier 33.6 Internal Plug & Play */
+       {       ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1580) },
+       /* Motorola OnlineSURFR 28.8 Internal Plug & Play */
+       {       ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x15B0) },
+       /* Motorola VoiceSURFR 56K Internal PnP */
+       {       ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x15F0) },
+       /* Com 1 */
+       /*  Deskline K56 Phone System PnP */
+       {       ISAPNP_VENDOR('M', 'V', 'X'), ISAPNP_DEVICE(0x00A1) },
+       /* PC Rider K56 Phone System PnP */
+       {       ISAPNP_VENDOR('M', 'V', 'X'), ISAPNP_DEVICE(0x00F2) },
+       /* Pace 56 Voice Internal Plug & Play Modem */
+       {       ISAPNP_VENDOR('P', 'M', 'C'), ISAPNP_DEVICE(0x2430) },
+       /* Generic */
+       /* Generic standard PC COM port  */
+       {       ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0500) },
+       /* Generic 16550A-compatible COM port */
+       {       ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0501) },
+       /* Compaq 14400 Modem */
+       {       ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC000) },
+       /* Compaq 2400/9600 Modem */
+       {       ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC001) },
+       /* Dial-Up Networking Serial Cable between 2 PCs */
+       {       ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC031) },
+       /* Dial-Up Networking Parallel Cable between 2 PCs */
+       {       ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC032) },
+       /* Standard 9600 bps Modem */
+       {       ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC100) },
+       /* Standard 14400 bps Modem */
+       {       ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC101) },
+       /*  Standard 28800 bps Modem*/
+       {       ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC102) },
+       /*  Standard Modem*/
+       {       ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC103) },
+       /*  Standard 9600 bps Modem*/
+       {       ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC104) },
+       /*  Standard 14400 bps Modem*/
+       {       ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC105) },
+       /*  Standard 28800 bps Modem*/
+       {       ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC106) },
+       /*  Standard Modem */
+       {       ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC107) },
+       /* Standard 9600 bps Modem */
+       {       ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC108) },
+       /* Standard 14400 bps Modem */
+       {       ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC109) },
+       /* Standard 28800 bps Modem */
+       {       ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10A) },
+       /* Standard Modem */
+       {       ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10B) },
+       /* Standard 9600 bps Modem */
+       {       ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10C) },
+       /* Standard 14400 bps Modem */
+       {       ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10D) },
+       /* Standard 28800 bps Modem */
+       {       ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10E) },
+       /* Standard Modem */
+       {       ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10F) },
+       /* Standard PCMCIA Card Modem */
+       {       ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x2000) },
+       /* Rockwell */
+       /* Modular Technology */
+       /* Rockwell 33.6 DPF Internal PnP */
+       /* Modular Technology 33.6 Internal PnP */
+       {       ISAPNP_VENDOR('R', 'O', 'K'), ISAPNP_DEVICE(0x0030) },
+       /* Kortex International */
+       /* KORTEX 14400 Externe PnP */
+       {       ISAPNP_VENDOR('R', 'O', 'K'), ISAPNP_DEVICE(0x0100) },
+       /* Viking Components, Inc */
+       /* Viking 28.8 INTERNAL Fax+Data+Voice PnP */
+       {       ISAPNP_VENDOR('R', 'O', 'K'), ISAPNP_DEVICE(0x4920) },
+       /* Rockwell */
+       /* British Telecom */
+       /* Modular Technology */
+       /* Rockwell 33.6 DPF External PnP */
+       /* BT Prologue 33.6 External PnP */
+       /* Modular Technology 33.6 External PnP */
+       {       ISAPNP_VENDOR('R', 'S', 'S'), ISAPNP_DEVICE(0x00A0) },
+       /* Viking 56K FAX INT */
+       {       ISAPNP_VENDOR('R', 'S', 'S'), ISAPNP_DEVICE(0x0262) },
+       /* SupraExpress 28.8 Data/Fax PnP modem */
+       {       ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1310) },
+       /* SupraExpress 33.6 Data/Fax PnP modem */
+       {       ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1421) },
+       /* SupraExpress 33.6 Data/Fax PnP modem */
+       {       ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1590) },
+       /* SupraExpress 33.6 Data/Fax PnP modem */
+       {       ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1760) },
+       /* Phoebe Micro */
+       /* Phoebe Micro 33.6 Data Fax 1433VQH Plug & Play */
+       {       ISAPNP_VENDOR('T', 'E', 'X'), ISAPNP_DEVICE(0x0011) },
+       /* Archtek America Corp. */
+       /* Archtek SmartLink Modem 3334BT Plug & Play */
+       {       ISAPNP_VENDOR('U', 'A', 'C'), ISAPNP_DEVICE(0x000F) },
+       /* 3Com Corp. */
+       /* Gateway Telepath IIvi 33.6 */
+       {       ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0000) },
+       /*  Sportster Vi 14.4 PnP FAX Voicemail */
+       {       ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0004) },
+       /* U.S. Robotics 33.6K Voice INT PnP */
+       {       ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0006) },
+       /* U.S. Robotics 33.6K Voice EXT PnP */
+       {       ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0007) },
+       /* U.S. Robotics 33.6K Voice INT PnP */
+       {       ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x2002) },
+       /* U.S. Robotics 56K Voice INT PnP */
+       {       ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x2070) },
+       /* U.S. Robotics 56K Voice EXT PnP */
+       {       ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x2080) },
+       /* U.S. Robotics 56K FAX INT */
+       {       ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3031) },
+       /* U.S. Robotics 56K Voice INT PnP */
+       {       ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3070) },
+       /* U.S. Robotics 56K Voice EXT PnP */
+       {       ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3080) },
+       /* U.S. Robotics 56K Voice INT PnP */
+       {       ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3090) },
+       /* U.S. Robotics 56K Message  */
+       {       ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9100) },
+       /*  U.S. Robotics 56K FAX EXT PnP*/
+       {       ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9160) },
+       /*  U.S. Robotics 56K FAX INT PnP*/
+       {       ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9170) },
+       /*  U.S. Robotics 56K Voice EXT PnP*/
+       {       ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9180) },
+       /*  U.S. Robotics 56K Voice INT PnP*/
+       {       ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9190) },
+       {       0, }
+};
+
+static inline void avoid_irq_share(struct pci_dev *dev)
+{
+       int i, map = 0x1FF8;
+       struct serial_state *state = rs_table;
+       struct isapnp_irq *irq;
+       struct isapnp_resources *res = dev->sysdata;
+
+       for (i = 0; i < NR_PORTS; i++) {
+               if (state->type != PORT_UNKNOWN)
+                       clear_bit(state->irq, &map);
+               state++;
+       }
+
+       for ( ; res; res = res->alt)
+               for(irq = res->irq; irq; irq = irq->next)
+                       irq->map = map;
+}
+
+static char *modem_names[] __devinitdata = {
+       "MODEM", "Modem", "modem", "FAX", "Fax", "fax",
+       "56K", "56k", "K56", "33.6", "28.8", "14.4",
+       "33,600", "28,800", "14,400", "33.600", "28.800", "14.400",
+       "33600", "28800", "14400", "V.90", "V.34", "V.32", 0
+};
+
+static int __devinit check_name(char *name)
+{
+       char **tmp = modem_names;
+
+       while (*tmp) {
+               if (strstr(name, *tmp))
+                       return 1;
+               tmp++;
+       }
+       return 0;
+}
+
+static inline int check_compatible_id(struct pci_dev *dev)
+{
+       int i;
+       for (i = 0; i < DEVICE_COUNT_COMPATIBLE; i++)
+              if ((dev->vendor_compatible[i] ==
+                   ISAPNP_VENDOR('P', 'N', 'P')) &&
+                  (swab16(dev->device_compatible[i]) >= 0xc000) &&
+                  (swab16(dev->device_compatible[i]) <= 0xdfff))
+                      return 0;
+       return 1;
+}
+
+/*
+ * Given a complete unknown ISA PnP device, try to use some heuristics to
+ * detect modems. Currently use such heuristic set:
+ *     - dev->name or dev->bus->name must contain "modem" substring;
+ *     - device must have only one IO region (8 byte long) with base adress
+ *       0x2e8, 0x3e8, 0x2f8 or 0x3f8.
+ *
+ * Such detection looks very ugly, but can detect at least some of numerous
+ * ISA PnP modems, alternatively we must hardcode all modems in pnp_devices[]
+ * table.
+ */
+static int _INLINE_ serial_pnp_guess_board(struct pci_dev *dev,
+                                         struct pci_board *board)
+{
+       struct isapnp_resources *res = (struct isapnp_resources *)dev->sysdata;
+       struct isapnp_resources *resa;
+
+       if (!(check_name(dev->name) || check_name(dev->bus->name)) &&
+          !(check_compatible_id(dev)))
+              return 1;
+
+       if (!res || res->next)
+              return 1;
+
+       for (resa = res->alt; resa; resa = resa->alt) {
+              struct isapnp_port *port;
+              for (port = res->port; port; port = port->next)
+                      if ((port->size == 8) &&
+                          ((port->min == 0x2f8) ||
+                           (port->min == 0x3f8) ||
+                           (port->min == 0x2e8) ||
+                           (port->min == 0x3e8)))
+                              return 0;
+       }
+
+       return 1;
+}
+
+static void __devinit probe_serial_pnp(void)
+{
+       struct pci_dev *dev = NULL;
+       struct pnp_board *pnp_board;
+       struct pci_board board;
+
+#ifdef SERIAL_DEBUG_PNP
+       printk("Entered probe_serial_pnp()\n");
+#endif
+       if (!isapnp_present()) {
+#ifdef SERIAL_DEBUG_PNP
+               printk("Leaving probe_serial_pnp() (no isapnp)\n");
+#endif
+               return;
+       }
+
+       isapnp_for_each_dev(dev) {
+              if (dev->active)
+                      continue;
+
+              memset(&board, 0, sizeof(board));
+              board.flags = SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT;
+              board.num_ports = 1;
+              board.base_baud = 115200;
+              
+              for (pnp_board = pnp_devices; pnp_board->vendor; pnp_board++)
+                      if ((dev->vendor == pnp_board->vendor) &&
+                          (dev->device == pnp_board->device))
+                              break;
+
+              if (pnp_board->vendor) {
+                      /* Special case that's more efficient to hardcode */
+                      if ((pnp_board->vendor == ISAPNP_VENDOR('A', 'K', 'Y') &&
+                           pnp_board->device == ISAPNP_DEVICE(0x1021)))
+                              board.flags |= SPCI_FL_NO_SHIRQ;
+              } else {
+                      if (serial_pnp_guess_board(dev, &board))
+                              continue;
+              }
+              
+              if (board.flags & SPCI_FL_NO_SHIRQ)
+                      avoid_irq_share(dev);
+              start_pci_pnp_board(dev, &board);
+       }
+
+#ifdef SERIAL_DEBUG_PNP
+       printk("Leaving probe_serial_pnp() (probe finished)\n");
+#endif
+       return;
+}
+
+#endif /* ENABLE_SERIAL_PNP */
+
+/*
+ * The serial driver boot-time initialization code!
+ */
+static int __init rs_init(void)
+{
+       int i;
+       struct serial_state * state;
+
+       init_bh(SERIAL_BH, do_serial_bh);
+       init_timer(&serial_timer);
+       serial_timer.function = rs_timer;
+       mod_timer(&serial_timer, jiffies + RS_STROBE_TIME);
+
+       for (i = 0; i < NR_IRQS; i++) {
+               IRQ_ports[i] = 0;
+               IRQ_timeout[i] = 0;
+#ifdef CONFIG_SERIAL_MULTIPORT
+               memset(&rs_multiport[i], 0,
+                      sizeof(struct rs_multiport_struct));
+#endif
+       }
+#ifdef CONFIG_SERIAL_CONSOLE
+       /*
+        *      The interrupt of the serial console port
+        *      can't be shared.
+        */
+       if (sercons.flags & CON_CONSDEV) {
+               for(i = 0; i < NR_PORTS; i++)
+                       if (i != sercons.index &&
+                           rs_table[i].irq == rs_table[sercons.index].irq)
+                               rs_table[i].irq = 0;
+       }
+#endif
+       show_serial_version();
+
+       /* Initialize the tty_driver structure */
+       
+       memset(&serial_driver, 0, sizeof(struct tty_driver));
+       serial_driver.magic = TTY_DRIVER_MAGIC;
+#if (LINUX_VERSION_CODE > 0x20100)
+       serial_driver.driver_name = "serial";
+#endif
+#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS))
+       serial_driver.name = "tts/%d";
+#else
+       serial_driver.name = "ttyS";
+#endif
+       serial_driver.major = TTY_MAJOR;
+       serial_driver.minor_start = 64 + SERIAL_DEV_OFFSET;
+       serial_driver.name_base = SERIAL_DEV_OFFSET;
+       serial_driver.num = NR_PORTS;
+       serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
+       serial_driver.subtype = SERIAL_TYPE_NORMAL;
+       serial_driver.init_termios = tty_std_termios;
+       serial_driver.init_termios.c_cflag =
+               B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+       serial_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
+       serial_driver.refcount = &serial_refcount;
+       serial_driver.table = serial_table;
+       serial_driver.termios = serial_termios;
+       serial_driver.termios_locked = serial_termios_locked;
+
+       serial_driver.open = rs_open;
+       serial_driver.close = rs_close;
+       serial_driver.write = rs_write;
+       serial_driver.put_char = rs_put_char;
+       serial_driver.flush_chars = rs_flush_chars;
+       serial_driver.write_room = rs_write_room;
+       serial_driver.chars_in_buffer = rs_chars_in_buffer;
+       serial_driver.flush_buffer = rs_flush_buffer;
+       serial_driver.ioctl = rs_ioctl;
+       serial_driver.throttle = rs_throttle;
+       serial_driver.unthrottle = rs_unthrottle;
+       serial_driver.set_termios = rs_set_termios;
+       serial_driver.stop = rs_stop;
+       serial_driver.start = rs_start;
+       serial_driver.hangup = rs_hangup;
+#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
+       serial_driver.break_ctl = rs_break;
+#endif
+#if (LINUX_VERSION_CODE >= 131343)
+       serial_driver.send_xchar = rs_send_xchar;
+       serial_driver.wait_until_sent = rs_wait_until_sent;
+       serial_driver.read_proc = rs_read_proc;
+#endif
+       
+       /*
+        * The callout device is just like normal device except for
+        * major number and the subtype code.
+        */
+       callout_driver = serial_driver;
+#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS))
+       callout_driver.name = "cua/%d";
+#else
+       callout_driver.name = "cua";
+#endif
+       callout_driver.major = TTYAUX_MAJOR;
+       callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+#if (LINUX_VERSION_CODE >= 131343)
+       callout_driver.read_proc = 0;
+       callout_driver.proc_entry = 0;
+#endif
+
+       if (tty_register_driver(&serial_driver))
+               panic("Couldn't register serial driver\n");
+       if (tty_register_driver(&callout_driver))
+               panic("Couldn't register callout driver\n");
+       
+       for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
+               state->magic = SSTATE_MAGIC;
+               state->line = i;
+               state->type = PORT_UNKNOWN;
+               state->custom_divisor = 0;
+               state->close_delay = 5*HZ/10;
+               state->closing_wait = 30*HZ;
+               state->callout_termios = callout_driver.init_termios;
+               state->normal_termios = serial_driver.init_termios;
+               state->icount.cts = state->icount.dsr = 
+                       state->icount.rng = state->icount.dcd = 0;
+               state->icount.rx = state->icount.tx = 0;
+               state->icount.frame = state->icount.parity = 0;
+               state->icount.overrun = state->icount.brk = 0;
+               state->irq = irq_cannonicalize(state->irq);
+               if (state->hub6)
+                       state->io_type = SERIAL_IO_HUB6;
+               if (state->port && check_region(state->port,8))
+                       continue;
+#ifdef CONFIG_MCA                      
+               if ((state->flags & ASYNC_BOOT_ONLYMCA) && !MCA_bus)
+                       continue;
+#endif                 
+               if (state->flags & ASYNC_BOOT_AUTOCONF)
+                       autoconfig(state);
+       }
+       for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
+               if (state->type == PORT_UNKNOWN)
+                       continue;
+               if (   (state->flags & ASYNC_BOOT_AUTOCONF)
+                   && (state->flags & ASYNC_AUTO_IRQ)
+                   && (state->port != 0 || state->iomem_base != 0))
+                       state->irq = detect_uart_irq(state);
+               if (state->io_type == SERIAL_IO_MEM) {
+                       printk(KERN_INFO"ttyS%02d%s at 0x%p (irq = %d) is a 
%s\n",
+                              state->line + SERIAL_DEV_OFFSET,
+                              (state->flags & ASYNC_FOURPORT) ? " FourPort" : 
"",
+                              state->iomem_base, state->irq,
+                              uart_config[state->type].name);
+               }
+               else {
+                       printk(KERN_INFO "ttyS%02d%s at 0x%04lx (irq = %d) is a 
%s\n",
+                              state->line + SERIAL_DEV_OFFSET,
+                              (state->flags & ASYNC_FOURPORT) ? " FourPort" : 
"",
+                              state->port, state->irq,
+                              uart_config[state->type].name);
+               }
+               tty_register_devfs(&serial_driver, 0,
+                                  serial_driver.minor_start + state->line);
+               tty_register_devfs(&callout_driver, 0,
+                                  callout_driver.minor_start + state->line);
+       }
+#ifdef ENABLE_SERIAL_PCI
+       probe_serial_pci();
+#endif
+#ifdef ENABLE_SERIAL_PNP
+       probe_serial_pnp();
+#endif
+       return 0;
+}
+
+/*
+ * This is for use by architectures that know their serial console 
+ * attributes only at run time. Not to be invoked after rs_init().
+ */
+int __init early_serial_setup(struct serial_struct *req)
+{
+       int i = req->line;
+
+       if (i >= NR_IRQS)
+               return(-ENOENT);
+       rs_table[i].magic = 0;
+       rs_table[i].baud_base = req->baud_base;
+       rs_table[i].port = req->port;
+       if (HIGH_BITS_OFFSET)
+               rs_table[i].port += (unsigned long) req->port_high << 
+                                                       HIGH_BITS_OFFSET;
+       rs_table[i].irq = req->irq;
+       rs_table[i].flags = req->flags;
+       rs_table[i].close_delay = req->close_delay;
+       rs_table[i].io_type = req->io_type;
+       rs_table[i].hub6 = req->hub6;
+       rs_table[i].iomem_base = req->iomem_base;
+       rs_table[i].iomem_reg_shift = req->iomem_reg_shift;
+       rs_table[i].type = req->type;
+       rs_table[i].xmit_fifo_size = req->xmit_fifo_size;
+       rs_table[i].custom_divisor = req->custom_divisor;
+       rs_table[i].closing_wait = req->closing_wait;
+       return(0);
+}
+
+/*
+ * register_serial and unregister_serial allows for 16x50 serial ports to be
+ * configured at run-time, to support PCMCIA modems.
+ */
+ 
+/**
+ *     register_serial - configure a 16x50 serial port at runtime
+ *     @req: request structure
+ *
+ *     Configure the serial port specified by the request. If the
+ *     port exists and is in use an error is returned. If the port
+ *     is not currently in the table it is added.
+ *
+ *     The port is then probed and if neccessary the IRQ is autodetected
+ *     If this fails an error is returned.
+ *
+ *     On success the port is ready to use and the line number is returned.
+ */
+ 
+int register_serial(struct serial_struct *req)
+{
+       int i;
+       unsigned long flags;
+       struct serial_state *state;
+       struct async_struct *info;
+       unsigned long port;
+
+       port = req->port;
+       if (HIGH_BITS_OFFSET)
+               port += (unsigned long) req->port_high << HIGH_BITS_OFFSET;
+
+       save_flags(flags); cli();
+       for (i = 0; i < NR_PORTS; i++) {
+               if ((rs_table[i].port == port) &&
+                   (rs_table[i].iomem_base == req->iomem_base))
+                       break;
+       }
+#ifdef __i386__
+       if (i == NR_PORTS) {
+               for (i = 4; i < NR_PORTS; i++)
+                       if ((rs_table[i].type == PORT_UNKNOWN) &&
+                           (rs_table[i].count == 0))
+                               break;
+       }
+#endif
+       if (i == NR_PORTS) {
+               for (i = 0; i < NR_PORTS; i++)
+                       if ((rs_table[i].type == PORT_UNKNOWN) &&
+                           (rs_table[i].count == 0))
+                               break;
+       }
+       if (i == NR_PORTS) {
+               restore_flags(flags);
+               return -1;
+       }
+       state = &rs_table[i];
+       if (rs_table[i].count) {
+               restore_flags(flags);
+               printk("Couldn't configure serial #%d (port=%ld,irq=%d): "
+                      "device already open\n", i, port, req->irq);
+               return -1;
+       }
+       state->irq = req->irq;
+       state->port = port;
+       state->flags = req->flags;
+       state->io_type = req->io_type;
+       state->iomem_base = req->iomem_base;
+       state->iomem_reg_shift = req->iomem_reg_shift;
+       if (req->baud_base)
+               state->baud_base = req->baud_base;
+       if ((info = state->info) != NULL) {
+               info->port = port;
+               info->flags = req->flags;
+               info->io_type = req->io_type;
+               info->iomem_base = req->iomem_base;
+               info->iomem_reg_shift = req->iomem_reg_shift;
+       }
+       autoconfig(state);
+       if (state->type == PORT_UNKNOWN) {
+               restore_flags(flags);
+               printk("register_serial(): autoconfig failed\n");
+               return -1;
+       }
+       restore_flags(flags);
+
+       if ((state->flags & ASYNC_AUTO_IRQ) && CONFIGURED_SERIAL_PORT(state))
+               state->irq = detect_uart_irq(state);
+
+       printk(KERN_INFO "ttyS%02d at %s 0x%04lx (irq = %d) is a %s\n",
+             state->line + SERIAL_DEV_OFFSET,
+             state->iomem_base ? "iomem" : "port",
+             state->iomem_base ? (unsigned long)state->iomem_base :
+             state->port, state->irq, uart_config[state->type].name);
+       tty_register_devfs(&serial_driver, 0,
+                          serial_driver.minor_start + state->line); 
+       tty_register_devfs(&callout_driver, 0,
+                          callout_driver.minor_start + state->line);
+       return state->line + SERIAL_DEV_OFFSET;
+}
+
+/**
+ *     unregister_serial - deconfigure a 16x50 serial port
+ *     @line: line to deconfigure
+ *
+ *     The port specified is deconfigured and its resources are freed. Any
+ *     user of the port is disconnected as if carrier was dropped. Line is
+ *     the port number returned by register_serial().
+ */
+
+void unregister_serial(int line)
+{
+       unsigned long flags;
+       struct serial_state *state = &rs_table[line];
+
+       save_flags(flags); cli();
+       if (state->info && state->info->tty)
+               tty_hangup(state->info->tty);
+       state->type = PORT_UNKNOWN;
+       printk(KERN_INFO "ttyS%02d unloaded\n", state->line);
+       /* These will be hidden, because they are devices that will no longer
+        * be available to the system. (ie, PCMCIA modems, once ejected)
+        */
+       tty_unregister_devfs(&serial_driver,
+                            serial_driver.minor_start + state->line);
+       tty_unregister_devfs(&callout_driver,
+                            callout_driver.minor_start + state->line);
+       restore_flags(flags);
+}
+
+static void __exit rs_fini(void) 
+{
+       unsigned long flags;
+       int e1, e2;
+       int i;
+       struct async_struct *info;
+
+       /* printk("Unloading %s: version %s\n", serial_name, serial_version); */
+       del_timer_sync(&serial_timer);
+       save_flags(flags); cli();
+        remove_bh(SERIAL_BH);
+       if ((e1 = tty_unregister_driver(&serial_driver)))
+               printk("serial: failed to unregister serial driver (%d)\n",
+                      e1);
+       if ((e2 = tty_unregister_driver(&callout_driver)))
+               printk("serial: failed to unregister callout driver (%d)\n", 
+                      e2);
+       restore_flags(flags);
+
+       for (i = 0; i < NR_PORTS; i++) {
+               if ((info = rs_table[i].info)) {
+                       rs_table[i].info = NULL;
+                       kfree(info);
+               }
+               if ((rs_table[i].type != PORT_UNKNOWN) && rs_table[i].port) {
+#ifdef CONFIG_SERIAL_RSA
+                       if (rs_table[i].type == PORT_RSA)
+                               release_region(rs_table[i].port +
+                                              UART_RSA_BASE, 16);
+                       else
+#endif
+                               release_region(rs_table[i].port, 8);
+               }
+#if defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP)
+               if (rs_table[i].iomem_base)
+                       iounmap(rs_table[i].iomem_base);
+#endif
+       }
+#if defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP)
+       for (i=0; i < NR_PCI_BOARDS; i++) {
+               struct pci_board_inst *brd = &serial_pci_board[i];
+
+               if (serial_pci_board[i].dev == 0)
+                       continue;
+               if (brd->board.init_fn)
+                       (brd->board.init_fn)(brd->dev, &brd->board, 0);
+               if (DEACTIVATE_FUNC(brd->dev))
+                       (DEACTIVATE_FUNC(brd->dev))(brd->dev);
+       }
+#endif 
+       if (tmp_buf) {
+               unsigned long pg = (unsigned long) tmp_buf;
+               tmp_buf = NULL;
+               free_page(pg);
+       }
+       
+#ifdef ENABLE_SERIAL_PCI
+       if (serial_pci_driver.name[0])
+               pci_unregister_driver (&serial_pci_driver);
+#endif
+}
+
+module_init(rs_init);
+module_exit(rs_fini);
+MODULE_DESCRIPTION("Standard/generic (dumb) serial driver");
+MODULE_AUTHOR("Theodore Ts'o <tytso@mit.edu>");
+MODULE_LICENSE("GPL");
+
+
+/*
+ * ------------------------------------------------------------
+ * Serial console driver
+ * ------------------------------------------------------------
+ */
+#ifdef CONFIG_SERIAL_CONSOLE
+
+#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+
+static struct async_struct async_sercons;
+
+/*
+ *     Wait for transmitter & holding register to empty
+ */
+static inline void wait_for_xmitr(struct async_struct *info)
+{
+       unsigned int status, tmout = 1000000;
+
+       do {
+               status = serial_in(info, UART_LSR);
+
+               if (status & UART_LSR_BI)
+                       lsr_break_flag = UART_LSR_BI;
+               
+               if (--tmout == 0)
+                       break;
+       } while((status & BOTH_EMPTY) != BOTH_EMPTY);
+
+       /* Wait for flow control if necessary */
+       if (info->flags & ASYNC_CONS_FLOW) {
+               tmout = 1000000;
+               while (--tmout &&
+                      ((serial_in(info, UART_MSR) & UART_MSR_CTS) == 0));
+       }       
+}
+
+
+/*
+ *     Print a string to the serial port trying not to disturb
+ *     any possible real use of the port...
+ *
+ *     The console must be locked when we get here.
+ */
+static void serial_console_write(struct console *co, const char *s,
+                               unsigned count)
+{
+       static struct async_struct *info = &async_sercons;
+       int ier;
+       unsigned i;
+
+       /*
+        *      First save the IER then disable the interrupts
+        */
+       ier = serial_in(info, UART_IER);
+       serial_out(info, UART_IER, 0x00);
+
+       /*
+        *      Now, do each character
+        */
+       for (i = 0; i < count; i++, s++) {
+               wait_for_xmitr(info);
+
+               /*
+                *      Send the character out.
+                *      If a LF, also do CR...
+                */
+               serial_out(info, UART_TX, *s);
+               if (*s == 10) {
+                       wait_for_xmitr(info);
+                       serial_out(info, UART_TX, 13);
+               }
+       }
+
+       /*
+        *      Finally, Wait for transmitter & holding register to empty
+        *      and restore the IER
+        */
+       wait_for_xmitr(info);
+       serial_out(info, UART_IER, ier);
+}
+
+static kdev_t serial_console_device(struct console *c)
+{
+       return MKDEV(TTY_MAJOR, 64 + c->index);
+}
+
+/*
+ *     Setup initial baud/bits/parity/flow control. We do two things here:
+ *     - construct a cflag setting for the first rs_open()
+ *     - initialize the serial port
+ *     Return non-zero if we didn't find a serial port.
+ */
+static int __init serial_console_setup(struct console *co, char *options)
+{
+       static struct async_struct *info;
+       struct serial_state *state;
+       unsigned cval;
+       int     baud = 9600;
+       int     bits = 8;
+       int     parity = 'n';
+       int     doflow = 0;
+       int     cflag = CREAD | HUPCL | CLOCAL;
+       int     quot = 0;
+       char    *s;
+
+       if (options) {
+               baud = simple_strtoul(options, NULL, 10);
+               s = options;
+               while(*s >= '0' && *s <= '9')
+                       s++;
+               if (*s) parity = *s++;
+               if (*s) bits   = *s++ - '0';
+               if (*s) doflow = (*s++ == 'r');
+       }
+
+       /*
+        *      Now construct a cflag setting.
+        */
+       switch(baud) {
+               case 1200:
+                       cflag |= B1200;
+                       break;
+               case 2400:
+                       cflag |= B2400;
+                       break;
+               case 4800:
+                       cflag |= B4800;
+                       break;
+               case 19200:
+                       cflag |= B19200;
+                       break;
+               case 38400:
+                       cflag |= B38400;
+                       break;
+               case 57600:
+                       cflag |= B57600;
+                       break;
+               case 115200:
+                       cflag |= B115200;
+                       break;
+               case 9600:
+               default:
+                       cflag |= B9600;
+                       /*
+                        * Set this to a sane value to prevent a divide error
+                        */
+                       baud  = 9600;
+                       break;
+       }
+       switch(bits) {
+               case 7:
+                       cflag |= CS7;
+                       break;
+               default:
+               case 8:
+                       cflag |= CS8;
+                       break;
+       }
+       switch(parity) {
+               case 'o': case 'O':
+                       cflag |= PARODD;
+                       break;
+               case 'e': case 'E':
+                       cflag |= PARENB;
+                       break;
+       }
+       co->cflag = cflag;
+
+       /*
+        *      Divisor, bytesize and parity
+        */
+       state = rs_table + co->index;
+       if (doflow)
+               state->flags |= ASYNC_CONS_FLOW;
+       info = &async_sercons;
+       info->magic = SERIAL_MAGIC;
+       info->state = state;
+       info->port = state->port;
+       info->flags = state->flags;
+#ifdef CONFIG_HUB6
+       info->hub6 = state->hub6;
+#endif
+       info->io_type = state->io_type;
+       info->iomem_base = state->iomem_base;
+       info->iomem_reg_shift = state->iomem_reg_shift;
+       quot = state->baud_base / baud;
+       cval = cflag & (CSIZE | CSTOPB);
+#if defined(__powerpc__) || defined(__alpha__)
+       cval >>= 8;
+#else /* !__powerpc__ && !__alpha__ */
+       cval >>= 4;
+#endif /* !__powerpc__ && !__alpha__ */
+       if (cflag & PARENB)
+               cval |= UART_LCR_PARITY;
+       if (!(cflag & PARODD))
+               cval |= UART_LCR_EPAR;
+
+       /*
+        *      Disable UART interrupts, set DTR and RTS high
+        *      and set speed.
+        */
+       serial_out(info, UART_LCR, cval | UART_LCR_DLAB);       /* set DLAB */
+       serial_out(info, UART_DLL, quot & 0xff);        /* LS of divisor */
+       serial_out(info, UART_DLM, quot >> 8);          /* MS of divisor */
+       serial_out(info, UART_LCR, cval);               /* reset DLAB */
+       serial_out(info, UART_IER, 0);
+       serial_out(info, UART_MCR, UART_MCR_DTR | UART_MCR_RTS);
+
+       /*
+        *      If we read 0xff from the LSR, there is no UART here.
+        */
+       if (serial_in(info, UART_LSR) == 0xff)
+               return -1;
+
+       return 0;
+}
+
+static struct console sercons = {
+       name:           "ttyS",
+       write:          serial_console_write,
+       device:         serial_console_device,
+       setup:          serial_console_setup,
+       flags:          CON_PRINTBUFFER,
+       index:          -1,
+};
+
+/*
+ *     Register console.
+ */
+void __init serial_console_init(void)
+{
+       register_console(&sercons);
+}
+#endif
+
+/*
+  Local variables:
+  compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes 
-O2 -fomit-frame-pointer -fno-strict-aliasing -pipe -fno-strength-reduce 
-march=i586 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h   
-DEXPORT_SYMTAB -c serial.c"
+  End:
+*/
diff -urN linux/drivers/char/cyclades.c linux/drivers/char/cyclades.c
--- linux/drivers/char/cyclades.c       2004/12/27 04:13:42     1.27.2.4
+++ linux/drivers/char/cyclades.c       2005/09/23 20:41:22     1.27.2.5
@@ -2960,10 +2960,15 @@
 cy_write(struct tty_struct * tty, int from_user,
            const unsigned char *buf, int count)
 {
-  struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+  struct cyclades_port *info;
   unsigned long flags;
   int c, ret = 0;
 
+    if (!tty)
+       return 0;
+
+    info = (struct cyclades_port *)tty->driver_data;
+  
 #ifdef CY_DEBUG_IO
     printk("cyc:cy_write ttyC%d\n", info->line); /* */
 #endif
@@ -2972,7 +2977,7 @@
         return 0;
     }
         
-    if (!tty || !info->xmit_buf || !tmp_buf){
+    if (!info->xmit_buf || !tmp_buf){
         return 0;
     }
 
@@ -3047,9 +3052,14 @@
 static void
 cy_put_char(struct tty_struct *tty, unsigned char ch)
 {
-  struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+  struct cyclades_port *info;
   unsigned long flags;
 
+    if (!tty)
+        return;
+
+    info = (struct cyclades_port *)tty->driver_data;
+  
 #ifdef CY_DEBUG_IO
     printk("cyc:cy_put_char ttyC%d\n", info->line);
 #endif
@@ -3057,7 +3067,7 @@
     if (serial_paranoia_check(info, tty->device, "cy_put_char"))
         return;
 
-    if (!tty || !info->xmit_buf)
+    if (!info->xmit_buf)
         return;
 
     CY_LOCK(info, flags);
diff -urN linux/drivers/char/esp.c linux/drivers/char/esp.c
--- linux/drivers/char/esp.c    2004/12/27 04:13:42     1.21.2.2
+++ linux/drivers/char/esp.c    2005/09/23 20:41:22     1.21.2.3
@@ -1251,13 +1251,18 @@
 
 static void rs_put_char(struct tty_struct *tty, unsigned char ch)
 {
-       struct esp_struct *info = (struct esp_struct *)tty->driver_data;
+       struct esp_struct *info;
        unsigned long flags;
 
+       if (!tty)
+               return;
+
+       info = (struct esp_struct *)tty->driver_data;
+       
        if (serial_paranoia_check(info, tty->device, "rs_put_char"))
                return;
 
-       if (!tty || !info->xmit_buf)
+       if (!info->xmit_buf)
                return;
 
        save_flags(flags); cli();
@@ -1296,13 +1301,19 @@
                    const unsigned char *buf, int count)
 {
        int     c, t, ret = 0;
-       struct esp_struct *info = (struct esp_struct *)tty->driver_data;
+       struct esp_struct *info;
        unsigned long flags;
 
+
+       if (!tty)
+               return 0;
+       
+       info = (struct esp_struct *)tty->driver_data;
+
        if (serial_paranoia_check(info, tty->device, "rs_write"))
                return 0;
 
-       if (!tty || !info->xmit_buf || !tmp_buf)
+       if (!info->xmit_buf || !tmp_buf)
                return 0;
            
        if (from_user)
diff -urN linux/drivers/char/isicom.c linux/drivers/char/isicom.c
--- linux/drivers/char/isicom.c 2004/12/27 04:13:42     1.14.2.3
+++ linux/drivers/char/isicom.c 2005/09/23 20:41:22     1.14.2.4
@@ -1223,9 +1223,15 @@
 static int isicom_write(struct tty_struct * tty, int from_user,
                        const unsigned char * buf, int count)
 {
-       struct isi_port * port = (struct isi_port *) tty->driver_data;
+       struct isi_port * port;
        unsigned long flags;
        int cnt, total = 0;
+
+       if (!tty)
+               return 0;
+       
+       port = (struct isi_port *) tty->driver_data;
+       
 #ifdef ISICOM_DEBUG
        printk(KERN_DEBUG "ISICOM: isicom_write for port%d: %d bytes.\n",
                        port->channel+1, count);
@@ -1233,7 +1239,7 @@
        if (isicom_paranoia_check(port, tty->device, "isicom_write"))
                return 0;
        
-       if (!tty || !port->xmit_buf || !tmp_buf)
+       if (!port->xmit_buf || !tmp_buf)
                return 0;
        if (from_user)
                down(&tmp_buf_sem); /* acquire xclusive access to tmp_buf */
@@ -1281,13 +1287,18 @@
 /* put_char et all */
 static void isicom_put_char(struct tty_struct * tty, unsigned char ch)
 {
-       struct isi_port * port = (struct isi_port *) tty->driver_data;
+       struct isi_port * port;
        unsigned long flags;
+
+       if (!tty)
+               return;
+
+       port = (struct isi_port *) tty->driver_data;
        
        if (isicom_paranoia_check(port, tty->device, "isicom_put_char"))
                return;
        
-       if (!tty || !port->xmit_buf)
+       if (!port->xmit_buf)
                return;
 #ifdef ISICOM_DEBUG
        printk(KERN_DEBUG "ISICOM: put_char, port %d, char %c.\n", 
port->channel+1, ch);
diff -urN linux/drivers/char/mxser.c linux/drivers/char/mxser.c
--- linux/drivers/char/mxser.c  2004/12/27 04:13:43     1.11.2.5
+++ linux/drivers/char/mxser.c  2005/09/23 20:41:22     1.11.2.6
@@ -911,10 +911,15 @@
                       const unsigned char *buf, int count)
 {
        int c, total = 0;
-       struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+       struct mxser_struct *info;
        unsigned long flags;
 
-       if (!tty || !info->xmit_buf || !mxvar_tmp_buf)
+       if (!tty)
+               return (0);
+       
+       info = (struct mxser_struct *) tty->driver_data;
+       
+       if (!info->xmit_buf || !mxvar_tmp_buf)
                return (0);
 
        save_flags(flags);
@@ -979,10 +984,15 @@
 
 static void mxser_put_char(struct tty_struct *tty, unsigned char ch)
 {
-       struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+       struct mxser_struct *info;
        unsigned long flags;
 
-       if (!tty || !info->xmit_buf)
+       if (!tty)
+               return;
+
+       info = (struct mxser_struct *) tty->driver_data;
+       
+       if (!info->xmit_buf)
                return;
 
        save_flags(flags);
diff -urN linux/drivers/char/riscom8.c linux/drivers/char/riscom8.c
--- linux/drivers/char/riscom8.c        2004/12/27 04:13:43     1.16.2.1
+++ linux/drivers/char/riscom8.c        2005/09/23 20:41:22     1.16.2.2
@@ -1220,17 +1220,22 @@
 static int rc_write(struct tty_struct * tty, int from_user, 
                    const unsigned char *buf, int count)
 {
-       struct riscom_port *port = (struct riscom_port *)tty->driver_data;
+       struct riscom_port *port;
        struct riscom_board *bp;
        int c, total = 0;
        unsigned long flags;
+
+       if (!tty)
+               return 0;
+
+       port = (struct riscom_port *)tty->driver_data;
                                
        if (rc_paranoia_check(port, tty->device, "rc_write"))
                return 0;
        
        bp = port_Board(port);
 
-       if (!tty || !port->xmit_buf || !tmp_buf)
+       if (!port->xmit_buf || !tmp_buf)
                return 0;
 
        save_flags(flags);
@@ -1298,13 +1303,18 @@
 
 static void rc_put_char(struct tty_struct * tty, unsigned char ch)
 {
-       struct riscom_port *port = (struct riscom_port *)tty->driver_data;
+       struct riscom_port *port;
        unsigned long flags;
 
+       if (!tty)
+               return;
+
+       port = (struct riscom_port *)tty->driver_data;
+
        if (rc_paranoia_check(port, tty->device, "rc_put_char"))
                return;
 
-       if (!tty || !port->xmit_buf)
+       if (!port->xmit_buf)
                return;
 
        save_flags(flags); cli();
diff -urN linux/drivers/char/serial.c linux/drivers/char/serial.c
--- linux/drivers/char/Attic/serial.c   2004/12/27 04:13:43     1.62.2.12
+++ linux/drivers/char/Attic/serial.c   2005/09/23 20:41:22     1.62.2.13
@@ -1851,13 +1851,18 @@
 
 static void rs_put_char(struct tty_struct *tty, unsigned char ch)
 {
-       struct async_struct *info = (struct async_struct *)tty->driver_data;
+       struct async_struct *info;
        unsigned long flags;
 
+       if (!tty)
+               return;
+       
+       info =  (struct async_struct *)tty->driver_data;
+       
        if (serial_paranoia_check(info, tty->device, "rs_put_char"))
                return;
 
-       if (!tty || !info->xmit.buf)
+       if (!info->xmit.buf)
                return;
 
        save_flags(flags); cli();
@@ -1897,13 +1902,18 @@
                    const unsigned char *buf, int count)
 {
        int     c, ret = 0;
-       struct async_struct *info = (struct async_struct *)tty->driver_data;
+       struct async_struct *info;
        unsigned long flags;
                                
+       if (!tty)
+               return 0;
+
+       info = (struct async_struct *)tty->driver_data;
+       
        if (serial_paranoia_check(info, tty->device, "rs_write"))
                return 0;
 
-       if (!tty || !info->xmit.buf || !tmp_buf)
+       if (!info->xmit.buf || !tmp_buf)
                return 0;
 
        save_flags(flags);
diff -urN linux/drivers/char/specialix.c linux/drivers/char/specialix.c
--- linux/drivers/char/specialix.c      2004/12/27 04:13:43     1.17.2.2
+++ linux/drivers/char/specialix.c      2005/09/23 20:41:22     1.17.2.3
@@ -1600,17 +1600,22 @@
 static int sx_write(struct tty_struct * tty, int from_user, 
                     const unsigned char *buf, int count)
 {
-       struct specialix_port *port = (struct specialix_port *)tty->driver_data;
+       struct specialix_port *port;
        struct specialix_board *bp;
        int c, total = 0;
        unsigned long flags;
+
+       if (!tty)
+               return 0;
+
+       port = (struct specialix_port *)tty->driver_data;
                                
        if (sx_paranoia_check(port, tty->device, "sx_write"))
                return 0;
        
        bp = port_Board(port);
 
-       if (!tty || !port->xmit_buf || !tmp_buf)
+       if (!port->xmit_buf || !tmp_buf)
                return 0;
 
        save_flags(flags);
@@ -1676,13 +1681,18 @@
 
 static void sx_put_char(struct tty_struct * tty, unsigned char ch)
 {
-       struct specialix_port *port = (struct specialix_port *)tty->driver_data;
+       struct specialix_port *port;
        unsigned long flags;
 
+       if (!tty)
+               return;
+
+       port = (struct specialix_port *)tty->driver_data;
+
        if (sx_paranoia_check(port, tty->device, "sx_put_char"))
                return;
 
-       if (!tty || !port->xmit_buf)
+       if (!port->xmit_buf)
                return;
 
        save_flags(flags); cli();
diff -urN linux/drivers/md/md.c linux/drivers/md/md.c
--- linux/drivers/md/md.c       2003/08/13 17:19:18     1.15.2.9
+++ linux/drivers/md/md.c       2005/09/23 20:41:23     1.15.2.10
@@ -1271,148 +1271,164 @@
        memcpy (sb, freshest->sb, sizeof(*sb));
 
        /*
-        * at this point we have picked the 'best' superblock
-        * from all available superblocks.
-        * now we validate this superblock and kick out possibly
-        * failed disks.
+        * For multipathing, lots of things are different from "true"
+        * RAIDs.
+        * All rdev's could be read, so they are no longer faulty.
+        * As there is just one sb, trying to find changed devices via the
+        * this_disk pointer is useless too.
+        *
+        * lmb@suse.de, 2002-09-12
         */
-       ITERATE_RDEV(mddev,rdev,tmp) {
-               /*
-                * Kick all non-fresh devices
-                */
-               __u64 ev1, ev2;
-               ev1 = md_event(rdev->sb);
-               ev2 = md_event(sb);
-               ++ev1;
-               if (ev1 < ev2) {
-                       printk(KERN_WARNING "md: kicking non-fresh %s from 
array!\n",
-                                               partition_name(rdev->dev));
-                       kick_rdev_from_array(rdev);
-                       continue;
-               }
-       }
 
-       /*
-        * Fix up changed device names ... but only if this disk has a
-        * recent update time. Use faulty checksum ones too.
-        */
-       if (mddev->sb->level != -4)
-       ITERATE_RDEV(mddev,rdev,tmp) {
-               __u64 ev1, ev2, ev3;
-               if (rdev->faulty || rdev->alias_device) {
-                       MD_BUG();
-                       goto abort;
-               }
-               ev1 = md_event(rdev->sb);
-               ev2 = md_event(sb);
-               ev3 = ev2;
-               --ev3;
-               if ((rdev->dev != rdev->old_dev) &&
-                       ((ev1 == ev2) || (ev1 == ev3))) {
+       if (sb->level == -4) {
+               int desc_nr = 0;
+
+               /* ... and initialize from the current rdevs instead */
+               ITERATE_RDEV(mddev,rdev,tmp) {
                        mdp_disk_t *desc;
 
-                       printk(KERN_WARNING "md: device name has changed from 
%s to %s since last import!\n",
-                              partition_name(rdev->old_dev), 
partition_name(rdev->dev));
-                       if (rdev->desc_nr == -1) {
-                               MD_BUG();
-                               goto abort;
-                       }
+                       rdev->desc_nr=desc_nr;
+
                        desc = &sb->disks[rdev->desc_nr];
-                       if (rdev->old_dev != MKDEV(desc->major, desc->minor)) {
-                               MD_BUG();
-                               goto abort;
-                       }
-                       desc->major = MAJOR(rdev->dev);
-                       desc->minor = MINOR(rdev->dev);
-                       desc = &rdev->sb->this_disk;
+
+                       desc->number = desc_nr;
                        desc->major = MAJOR(rdev->dev);
                        desc->minor = MINOR(rdev->dev);
-               }
-       }
+                       desc->raid_disk = desc_nr;
 
-       /*
-        * Remove unavailable and faulty devices ...
-        *
-        * note that if an array becomes completely unrunnable due to
-        * missing devices, we do not write the superblock back, so the
-        * administrator has a chance to fix things up. The removal thus
-        * only happens if it's nonfatal to the contents of the array.
-        */
-       for (i = 0; i < MD_SB_DISKS; i++) {
-               int found;
-               mdp_disk_t *desc;
-               kdev_t dev;
+                       /* We could read from it, so it isn't faulty
+                        * any longer */
+                       if (disk_faulty(desc))
+                               mark_disk_spare(desc);
 
-               desc = sb->disks + i;
-               dev = MKDEV(desc->major, desc->minor);
+                       memcpy(&rdev->sb->this_disk,desc,sizeof(*desc));
+
+                       desc_nr++;
+               }
 
+               /* Kick out all old info about disks we used to have,
+                * if any */
+               for (i = desc_nr; i < MD_SB_DISKS; i++)
+                       memset(&(sb->disks[i]),0,sizeof(mdp_disk_t));
+       } else {
                /*
-                * We kick faulty devices/descriptors immediately.
-                *
-                * Note: multipath devices are a special case.  Since we
-                * were able to read the superblock on the path, we don't
-                * care if it was previously marked as faulty, it's up now
-                * so enable it.
+                * at this point we have picked the 'best' superblock
+                * from all available superblocks.
+                * now we validate this superblock and kick out possibly
+                * failed disks.
                 */
-               if (disk_faulty(desc) && mddev->sb->level != -4) {
-                       found = 0;
-                       ITERATE_RDEV(mddev,rdev,tmp) {
-                               if (rdev->desc_nr != desc->number)
-                                       continue;
-                               printk(KERN_WARNING "md%d: kicking faulty 
%s!\n",
-                                       mdidx(mddev),partition_name(rdev->dev));
-                               kick_rdev_from_array(rdev);
-                               found = 1;
-                               break;
-                       }
-                       if (!found) {
-                               if (dev == MKDEV(0,0))
-                                       continue;
-                               printk(KERN_WARNING "md%d: removing former 
faulty %s!\n",
-                                       mdidx(mddev), partition_name(dev));
-                       }
-                       remove_descriptor(desc, sb);
-                       continue;
-               } else if (disk_faulty(desc)) {
+               ITERATE_RDEV(mddev,rdev,tmp) {
                        /*
-                        * multipath entry marked as faulty, unfaulty it
+                        * Kick all non-fresh devices
                         */
-                       rdev = find_rdev(mddev, dev);
-                       if(rdev)
-                               mark_disk_spare(desc);
-                       else
-                               remove_descriptor(desc, sb);
+                       __u64 ev1, ev2;
+                       ev1 = md_event(rdev->sb);
+                       ev2 = md_event(sb);
+                       ++ev1;
+                       if (ev1 < ev2) {
+                               printk(KERN_WARNING "md: kicking non-fresh %s 
from array!\n",
+                                                       
partition_name(rdev->dev));
+                               kick_rdev_from_array(rdev);
+                               continue;
+                       }
                }
 
-               if (dev == MKDEV(0,0))
-                       continue;
                /*
-                * Is this device present in the rdev ring?
+                * Fix up changed device names ... but only if this disk has a
+                * recent update time. Use faulty checksum ones too.
                 */
-               found = 0;
                ITERATE_RDEV(mddev,rdev,tmp) {
+                       __u64 ev1, ev2, ev3;
+                       if (rdev->faulty || rdev->alias_device) {
+                               MD_BUG();
+                               goto abort;
+                       }
+                       ev1 = md_event(rdev->sb);
+                       ev2 = md_event(sb);
+                       ev3 = ev2;
+                       --ev3;
+                       if ((rdev->dev != rdev->old_dev) &&
+                               ((ev1 == ev2) || (ev1 == ev3))) {
+                               mdp_disk_t *desc;
+
+                               printk(KERN_WARNING "md: device name has 
changed from %s to %s since last import!\n",
+                                      partition_name(rdev->old_dev), 
partition_name(rdev->dev));
+                               if (rdev->desc_nr == -1) {
+                                       MD_BUG();
+                                       goto abort;
+                               }
+                               desc = &sb->disks[rdev->desc_nr];
+                               if (rdev->old_dev != MKDEV(desc->major, 
desc->minor)) {
+                                       MD_BUG();
+                                       goto abort;
+                               }
+                               desc->major = MAJOR(rdev->dev);
+                               desc->minor = MINOR(rdev->dev);
+                               desc = &rdev->sb->this_disk;
+                               desc->major = MAJOR(rdev->dev);
+                               desc->minor = MINOR(rdev->dev);
+                       }
+               }
+
+               /*
+                * Remove unavailable and faulty devices ...
+                *
+                * note that if an array becomes completely unrunnable due to
+                * missing devices, we do not write the superblock back, so the
+                * administrator has a chance to fix things up. The removal thus
+                * only happens if it's nonfatal to the contents of the array.
+                */
+               for (i = 0; i < MD_SB_DISKS; i++) {
+                       int found;
+                       mdp_disk_t *desc;
+                       kdev_t dev;
+
+                       desc = sb->disks + i;
+                       dev = MKDEV(desc->major, desc->minor);
+
                        /*
-                        * Multi-path IO special-case: since we have no
-                        * this_disk descriptor at auto-detect time,
-                        * we cannot check rdev->number.
-                        * We can check the device though.
+                        * We kick faulty devices/descriptors immediately.
                         */
-                       if ((sb->level == -4) && (rdev->dev ==
-                                       MKDEV(desc->major,desc->minor))) {
-                               found = 1;
-                               break;
+                       if (disk_faulty(desc)) {
+                               found = 0;
+                               ITERATE_RDEV(mddev,rdev,tmp) {
+                                       if (rdev->desc_nr != desc->number)
+                                               continue;
+                                       printk(KERN_WARNING "md%d: kicking 
faulty %s!\n",
+                                               
mdidx(mddev),partition_name(rdev->dev));
+                                       kick_rdev_from_array(rdev);
+                                       found = 1;
+                                       break;
+                               }
+                               if (!found) {
+                                       if (dev == MKDEV(0,0))
+                                               continue;
+                                       printk(KERN_WARNING "md%d: removing 
former faulty %s!\n",
+                                               mdidx(mddev), 
partition_name(dev));
+                               }
+                               remove_descriptor(desc, sb);
+                               continue;
                        }
-                       if (rdev->desc_nr == desc->number) {
-                               found = 1;
-                               break;
+
+                       if (dev == MKDEV(0,0))
+                               continue;
+                       /*
+                        * Is this device present in the rdev ring?
+                        */
+                       found = 0;
+                       ITERATE_RDEV(mddev,rdev,tmp) {
+                               if (rdev->desc_nr == desc->number) {
+                                       found = 1;
+                                       break;
+                               }
                        }
-               }
-               if (found)
-                       continue;
+                       if (found)
+                               continue;
 
-               printk(KERN_WARNING "md%d: former device %s is unavailable, 
removing from array!\n",
-                      mdidx(mddev), partition_name(dev));
-               remove_descriptor(desc, sb);
+                       printk(KERN_WARNING "md%d: former device %s is 
unavailable, removing from array!\n",
+                              mdidx(mddev), partition_name(dev));
+                       remove_descriptor(desc, sb);
+               }
        }
 
        /*
diff -urN linux/drivers/scsi/ahci.c linux/drivers/scsi/ahci.c
--- linux/drivers/scsi/ahci.c   2005/05/23 12:12:31     1.2.2.5
+++ linux/drivers/scsi/ahci.c   2005/09/23 20:41:23     1.2.2.6
@@ -38,7 +38,8 @@
 #include <asm/io.h>
 
 #define DRV_NAME       "ahci"
-#define DRV_VERSION    "1.00"
+#define DRV_VERSION    "1.01"
+
 
 enum {
        AHCI_PCI_BAR            = 5,
@@ -48,6 +49,7 @@
        AHCI_CMD_SLOT_SZ        = 32 * 32,
        AHCI_RX_FIS_SZ          = 256,
        AHCI_CMD_TBL_HDR        = 0x80,
+       AHCI_CMD_TBL_CDB        = 0x40,
        AHCI_CMD_TBL_SZ         = AHCI_CMD_TBL_HDR + (AHCI_MAX_SG * 16),
        AHCI_PORT_PRIV_DMA_SZ   = AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_SZ +
                                  AHCI_RX_FIS_SZ,
@@ -132,6 +134,9 @@
        PORT_CMD_ICC_ACTIVE     = (0x1 << 28), /* Put i/f in active state */
        PORT_CMD_ICC_PARTIAL    = (0x2 << 28), /* Put i/f in partial state */
        PORT_CMD_ICC_SLUMBER    = (0x6 << 28), /* Put i/f in slumber state */
+
+       /* hpriv->flags bits */
+       AHCI_FLAG_MSI           = (1 << 0),
 };
 
 struct ahci_cmd_hdr {
@@ -181,13 +186,14 @@
 static u8 ahci_check_status(struct ata_port *ap);
 static u8 ahci_check_err(struct ata_port *ap);
 static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd 
*qc);
+static void ahci_remove_one (struct pci_dev *pdev);
 
 static Scsi_Host_Template ahci_sht = {
        .module                 = THIS_MODULE,
        .name                   = DRV_NAME,
-       .ioctl                  = ata_scsi_ioctl,
        .detect                 = ata_scsi_detect,
        .release                = ata_scsi_release,
+       .ioctl                  = ata_scsi_ioctl,
        .queuecommand           = ata_scsi_queuecmd,
        .eh_strategy_handler    = ata_scsi_error,
        .can_queue              = ATA_DEF_QUEUE,
@@ -256,6 +262,12 @@
          board_ahci }, /* ICH7R */
        { PCI_VENDOR_ID_AL, 0x5288, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
          board_ahci }, /* ULi M5288 */
+       { PCI_VENDOR_ID_INTEL, 0x2681, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+         board_ahci }, /* ESB2 */
+       { PCI_VENDOR_ID_INTEL, 0x2682, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+         board_ahci }, /* ESB2 */
+       { PCI_VENDOR_ID_INTEL, 0x2683, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+         board_ahci }, /* ESB2 */
        { }     /* terminate list */
 };
 
@@ -264,7 +276,7 @@
        .name                   = DRV_NAME,
        .id_table               = ahci_pci_tbl,
        .probe                  = ahci_init_one,
-       .remove                 = ata_pci_remove_one,
+       .remove                 = ahci_remove_one,
 };
 
 
@@ -282,6 +294,8 @@
 {
        struct ahci_host_priv *hpriv = host_set->private_data;
        kfree(hpriv);
+
+       ata_host_stop(host_set);
 }
 
 static int ahci_port_start(struct ata_port *ap)
@@ -289,26 +303,19 @@
        struct device *dev = ap->host_set->dev;
        struct ahci_host_priv *hpriv = ap->host_set->private_data;
        struct ahci_port_priv *pp;
-       int rc;
        void *mem, *mmio = ap->host_set->mmio_base;
        void *port_mmio = ahci_port_base(mmio, ap->port_no);
        dma_addr_t mem_dma;
 
-       rc = ata_port_start(ap);
-       if (rc)
-               return rc;
-
        pp = kmalloc(sizeof(*pp), GFP_KERNEL);
-       if (!pp) {
-               rc = -ENOMEM;
-               goto err_out;
-       }
+       if (!pp)
+               return -ENOMEM;
        memset(pp, 0, sizeof(*pp));
 
        mem = dma_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma, 
GFP_KERNEL);
        if (!mem) {
-               rc = -ENOMEM;
-               goto err_out_kfree;
+               kfree(pp);
+               return -ENOMEM;
        }
        memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ);
 
@@ -358,12 +365,6 @@
        readl(port_mmio + PORT_CMD); /* flush */
 
        return 0;
-
-err_out_kfree:
-       kfree(pp);
-err_out:
-       ata_port_stop(ap);
-       return rc;
 }
 
 
@@ -389,7 +390,6 @@
        dma_free_coherent(dev, AHCI_PORT_PRIV_DMA_SZ,
                          pp->cmd_slot, pp->cmd_slot_dma);
        kfree(pp);
-       ata_port_stop(ap);
 }
 
 static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in)
@@ -496,7 +496,8 @@
 
 static void ahci_qc_prep(struct ata_queued_cmd *qc)
 {
-       struct ahci_port_priv *pp = qc->ap->private_data;
+       struct ata_port *ap = qc->ap;
+       struct ahci_port_priv *pp = ap->private_data;
        u32 opts;
        const u32 cmd_fis_len = 5; /* five dwords */
 
@@ -508,18 +509,8 @@
        opts = (qc->n_elem << 16) | cmd_fis_len;
        if (qc->tf.flags & ATA_TFLAG_WRITE)
                opts |= AHCI_CMD_WRITE;
-
-       switch (qc->tf.protocol) {
-       case ATA_PROT_ATAPI:
-       case ATA_PROT_ATAPI_NODATA:
-       case ATA_PROT_ATAPI_DMA:
+       if (is_atapi_taskfile(&qc->tf))
                opts |= AHCI_CMD_ATAPI;
-               break;
-
-       default:
-               /* do nothing */
-               break;
-       }
 
        pp->cmd_slot[0].opts = cpu_to_le32(opts);
        pp->cmd_slot[0].status = 0;
@@ -531,6 +522,10 @@
         * a SATA Register - Host to Device command FIS.
         */
        ata_tf_to_fis(&qc->tf, pp->cmd_tbl, 0);
+       if (opts & AHCI_CMD_ATAPI) {
+               memset(pp->cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
+               memcpy(pp->cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, ap->cdb_len);
+       }
 
        if (!(qc->flags & ATA_QCFLAG_DMAMAP))
                return;
@@ -853,15 +848,19 @@
 }
 
 /* move to PCI layer, integrate w/ MSI stuff */
-static void pci_enable_intx(struct pci_dev *pdev)
+static void pci_intx(struct pci_dev *pdev, int enable)
 {
-       u16 pci_command;
+       u16 pci_command, new;
 
        pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
-       if (pci_command & PCI_COMMAND_INTX_DISABLE) {
-               pci_command &= ~PCI_COMMAND_INTX_DISABLE;
+
+       if (enable)
+               new = pci_command & ~PCI_COMMAND_INTX_DISABLE;
+       else
+               new = pci_command | PCI_COMMAND_INTX_DISABLE;
+
+       if (new != pci_command)
                pci_write_config_word(pdev, PCI_COMMAND, pci_command);
-       }
 }
 
 static void ahci_print_info(struct ata_probe_ent *probe_ent)
@@ -943,7 +942,7 @@
        unsigned long base;
        void *mmio_base;
        unsigned int board_idx = (unsigned int) ent->driver_data;
-       int pci_dev_busy = 0;
+       int have_msi, pci_dev_busy = 0;
        int rc;
 
        VPRINTK("ENTER\n");
@@ -961,12 +960,17 @@
                goto err_out;
        }
 
-       pci_enable_intx(pdev);
+       if (pci_enable_msi(pdev) == 0)
+               have_msi = 1;
+       else {
+               pci_intx(pdev, 1);
+               have_msi = 0;
+       }
 
        probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
        if (probe_ent == NULL) {
                rc = -ENOMEM;
-               goto err_out_regions;
+               goto err_out_msi;
        }
 
        memset(probe_ent, 0, sizeof(*probe_ent));
@@ -999,6 +1003,9 @@
        probe_ent->mmio_base = mmio_base;
        probe_ent->private_data = hpriv;
 
+       if (have_msi)
+               hpriv->flags |= AHCI_FLAG_MSI;
+
        /* initialize adapter */
        rc = ahci_host_init(probe_ent);
        if (rc)
@@ -1016,7 +1023,11 @@
        iounmap(mmio_base);
 err_out_free_ent:
        kfree(probe_ent);
-err_out_regions:
+err_out_msi:
+       if (have_msi)
+               pci_disable_msi(pdev);
+       else
+               pci_intx(pdev, 0);
        pci_release_regions(pdev);
 err_out:
        if (!pci_dev_busy)
@@ -1024,6 +1035,38 @@
        return rc;
 }
 
+static void ahci_remove_one (struct pci_dev *pdev)
+{
+       struct device *dev = pci_dev_to_dev(pdev);
+       struct ata_host_set *host_set = dev_get_drvdata(dev);
+       struct ahci_host_priv *hpriv = host_set->private_data;
+       struct ata_port *ap;
+       Scsi_Host_Template *sht;
+       int have_msi, rc;
+
+       /* FIXME: this unregisters all ports attached to the
+        * Scsi_Host_Template given.  We _might_ have multiple
+        * templates (though we don't ATM), so this is ok... for now.
+        */
+       ap = host_set->ports[0];
+       sht = ap->host->hostt;
+       rc = scsi_unregister_module(MODULE_SCSI_HA, sht);
+       /* FIXME: handle 'rc' failure? */
+
+       have_msi = hpriv->flags & AHCI_FLAG_MSI;
+       free_irq(host_set->irq, host_set);
+
+       host_set->ops->host_stop(host_set);
+       kfree(host_set);
+
+       if (have_msi)
+               pci_disable_msi(pdev);
+       else
+               pci_intx(pdev, 0);
+       pci_release_regions(pdev);
+       pci_disable_device(pdev);
+       dev_set_drvdata(dev, NULL);
+}
 
 static int __init ahci_init(void)
 {
diff -urN linux/drivers/scsi/ata_piix.c linux/drivers/scsi/ata_piix.c
--- linux/drivers/scsi/ata_piix.c       2005/03/18 12:13:27     1.16.2.4
+++ linux/drivers/scsi/ata_piix.c       2005/09/23 20:41:23     1.16.2.5
@@ -61,6 +61,7 @@
        ich6_sata               = 3,
        ich6_sata_rm            = 4,
        ich7_sata               = 5,
+       esb2_sata               = 6,
 };
 
 static int piix_init_one (struct pci_dev *pdev,
@@ -93,6 +94,7 @@
        { 0x8086, 0x2653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_rm },
        { 0x8086, 0x27c0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich7_sata },
        { 0x8086, 0x27c4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich7_sata },
+       { 0x8086, 0x2680, PCI_ANY_ID, PCI_ANY_ID, 0, 0, esb2_sata },
 
        { }     /* terminate list */
 };
@@ -151,6 +153,7 @@
 
        .port_start             = ata_port_start,
        .port_stop              = ata_port_stop,
+       .host_stop              = ata_host_stop,
 };
 
 static struct ata_port_operations piix_sata_ops = {
@@ -178,6 +181,7 @@
 
        .port_start             = ata_port_start,
        .port_stop              = ata_port_stop,
+       .host_stop              = ata_host_stop,
 };
 
 static struct ata_port_info piix_port_info[] = {
@@ -256,6 +260,18 @@
                .udma_mask      = 0x7f, /* udma0-6 */
                .port_ops       = &piix_sata_ops,
        },
+
+       /* esb2_sata */
+       {
+               .sht            = &piix_sht,
+               .host_flags     = ATA_FLAG_SATA | ATA_FLAG_SRST |
+                                 PIIX_FLAG_COMBINED | PIIX_FLAG_CHECKINTR |
+                                 ATA_FLAG_SLAVE_POSS | PIIX_FLAG_AHCI,
+               .pio_mask       = 0x1f, /* pio0-4 */
+               .mwdma_mask     = 0x07, /* mwdma0-2 */
+               .udma_mask      = 0x7f, /* udma0-6 */
+               .port_ops       = &piix_sata_ops,
+       },
 };
 
 static struct pci_bits piix_enable_bits[] = {
@@ -650,15 +666,6 @@
        return ata_pci_init_one(pdev, port_info, n_ports);
 }
 
-/**
- *     piix_init -
- *
- *     LOCKING:
- *
- *     RETURNS:
- *
- */
-
 static int __init piix_init(void)
 {
        int rc;
@@ -685,13 +692,6 @@
        return rc;
 }
 
-/**
- *     piix_exit -
- *
- *     LOCKING:
- *
- */
-
 static void __exit piix_exit(void)
 {
        scsi_unregister_module(MODULE_SCSI_HA, &piix_sht);
diff -urN linux/drivers/scsi/libata-core.c linux/drivers/scsi/libata-core.c
--- linux/drivers/scsi/libata-core.c    2005/03/18 12:13:27     1.16.2.6
+++ linux/drivers/scsi/libata-core.c    2005/09/23 20:41:23     1.16.2.7
@@ -185,6 +185,28 @@
        ata_wait_idle(ap);
 }
 
+
+/**
+ *     ata_tf_load - send taskfile registers to host controller
+ *     @ap: Port to which output is sent
+ *     @tf: ATA taskfile register set
+ *
+ *     Outputs ATA taskfile to standard ATA host controller using MMIO
+ *     or PIO as indicated by the ATA_FLAG_MMIO flag.
+ *     Writes the control, feature, nsect, lbal, lbam, and lbah registers.
+ *     Optionally (ATA_TFLAG_LBA48) writes hob_feature, hob_nsect,
+ *     hob_lbal, hob_lbam, and hob_lbah.
+ *
+ *     This function waits for idle (!BUSY and !DRQ) after writing
+ *     registers.  If the control register has a new value, this
+ *     function also waits for idle after writing control and before
+ *     writing the remaining registers.
+ *
+ *     May be used as the tf_load() entry in ata_port_operations.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
 void ata_tf_load(struct ata_port *ap, struct ata_taskfile *tf)
 {
        if (ap->flags & ATA_FLAG_MMIO)
@@ -194,11 +216,11 @@
 }
 
 /**
- *     ata_exec_command - issue ATA command to host controller
+ *     ata_exec_command_pio - issue ATA command to host controller
  *     @ap: port to which command is being issued
  *     @tf: ATA taskfile register set
  *
- *     Issues PIO/MMIO write to ATA command register, with proper
+ *     Issues PIO write to ATA command register, with proper
  *     synchronization with interrupt handler / other threads.
  *
  *     LOCKING:
@@ -234,6 +256,18 @@
        ata_pause(ap);
 }
 
+
+/**
+ *     ata_exec_command - issue ATA command to host controller
+ *     @ap: port to which command is being issued
+ *     @tf: ATA taskfile register set
+ *
+ *     Issues PIO/MMIO write to ATA command register, with proper
+ *     synchronization with interrupt handler / other threads.
+ *
+ *     LOCKING:
+ *     spin_lock_irqsave(host_set lock)
+ */
 void ata_exec_command(struct ata_port *ap, struct ata_taskfile *tf)
 {
        if (ap->flags & ATA_FLAG_MMIO)
@@ -304,7 +338,7 @@
 }
 
 /**
- *     ata_tf_read - input device's ATA taskfile shadow registers
+ *     ata_tf_read_pio - input device's ATA taskfile shadow registers
  *     @ap: Port from which input is read
  *     @tf: ATA taskfile register set for storing input
  *
@@ -367,6 +401,23 @@
        }
 }
 
+
+/**
+ *     ata_tf_read - input device's ATA taskfile shadow registers
+ *     @ap: Port from which input is read
+ *     @tf: ATA taskfile register set for storing input
+ *
+ *     Reads ATA taskfile registers for currently-selected device
+ *     into @tf.
+ *
+ *     Reads nsect, lbal, lbam, lbah, and device.  If ATA_TFLAG_LBA48
+ *     is set, also reads the hob registers.
+ *
+ *     May be used as the tf_read() entry in ata_port_operations.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
 void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
 {
        if (ap->flags & ATA_FLAG_MMIO)
@@ -380,7 +431,7 @@
  *     @ap: port where the device is
  *
  *     Reads ATA taskfile status register for currently-selected device
- *     and return it's value. This also clears pending interrupts
+ *     and return its value. This also clears pending interrupts
  *      from this device
  *
  *     LOCKING:
@@ -396,7 +447,7 @@
  *     @ap: port where the device is
  *
  *     Reads ATA taskfile status register for currently-selected device
- *     via MMIO and return it's value. This also clears pending interrupts
+ *     via MMIO and return its value. This also clears pending interrupts
  *      from this device
  *
  *     LOCKING:
@@ -407,6 +458,20 @@
                return readb((void __iomem *) ap->ioaddr.status_addr);
 }
 
+
+/**
+ *     ata_check_status - Read device status reg & clear interrupt
+ *     @ap: port where the device is
+ *
+ *     Reads ATA taskfile status register for currently-selected device
+ *     and return its value. This also clears pending interrupts
+ *      from this device
+ *
+ *     May be used as the check_status() entry in ata_port_operations.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
 u8 ata_check_status(struct ata_port *ap)
 {
        if (ap->flags & ATA_FLAG_MMIO)
@@ -414,6 +479,20 @@
        return ata_check_status_pio(ap);
 }
 
+
+/**
+ *     ata_altstatus - Read device alternate status reg
+ *     @ap: port where the device is
+ *
+ *     Reads ATA taskfile alternate status register for
+ *     currently-selected device and return its value.
+ *
+ *     Note: may NOT be used as the check_altstatus() entry in
+ *     ata_port_operations.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
 u8 ata_altstatus(struct ata_port *ap)
 {
        if (ap->ops->check_altstatus)
@@ -424,6 +503,20 @@
        return inb(ap->ioaddr.altstatus_addr);
 }
 
+
+/**
+ *     ata_chk_err - Read device error reg
+ *     @ap: port where the device is
+ *
+ *     Reads ATA taskfile error register for
+ *     currently-selected device and return its value.
+ *
+ *     Note: may NOT be used as the check_err() entry in
+ *     ata_port_operations.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
 u8 ata_chk_err(struct ata_port *ap)
 {
        if (ap->ops->check_err)
@@ -872,10 +965,24 @@
        }
 }
 
+
+/**
+ *     ata_noop_dev_select - Select device 0/1 on ATA bus
+ *     @ap: ATA channel to manipulate
+ *     @device: ATA device (numbered from zero) to select
+ *
+ *     This function performs no actual function.
+ *
+ *     May be used as the dev_select() entry in ata_port_operations.
+ *
+ *     LOCKING:
+ *     caller.
+ */
 void ata_noop_dev_select (struct ata_port *ap, unsigned int device)
 {
 }
 
+
 /**
  *     ata_std_dev_select - Select device 0/1 on ATA bus
  *     @ap: ATA channel to manipulate
@@ -883,7 +990,9 @@
  *
  *     Use the method defined in the ATA specification to
  *     make either device 0, or device 1, active on the
- *     ATA channel.
+ *     ATA channel.  Works with both PIO and MMIO.
+ *
+ *     May be used as the dev_select() entry in ata_port_operations.
  *
  *     LOCKING:
  *     caller.
@@ -1185,11 +1294,47 @@
        DPRINTK("EXIT, err\n");
 }
 
+
+static inline u8 ata_dev_knobble(struct ata_port *ap)
+{
+       return ((ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(ap->device->id)));
+}
+
+/**
+ *     ata_dev_config - Run device specific handlers and check for
+ *                      SATA->PATA bridges
+ *     @ap: Bus 
+ *     @i:  Device
+ *
+ *     LOCKING:
+ */
+ 
+void ata_dev_config(struct ata_port *ap, unsigned int i)
+{
+       /* limit bridge transfers to udma5, 200 sectors */
+       if (ata_dev_knobble(ap)) {
+               printk(KERN_INFO "ata%u(%u): applying bridge limits\n",
+                       ap->id, ap->device->devno);
+               ap->udma_mask &= ATA_UDMA5;
+               ap->host->max_sectors = ATA_MAX_SECTORS;
+               ap->host->hostt->max_sectors = ATA_MAX_SECTORS;
+               ap->device->flags |= ATA_DFLAG_LOCK_SECTORS;
+       }
+
+       if (ap->ops->dev_config)
+               ap->ops->dev_config(ap, &ap->device[i]);
+}
+
 /**
  *     ata_bus_probe - Reset and probe ATA bus
  *     @ap: Bus to probe
  *
+ *     Master ATA bus probing function.  Initiates a hardware-dependent
+ *     bus reset, then attempts to identify any devices found on
+ *     the bus.
+ *
  *     LOCKING:
+ *     PCI/etc. bus probe sem.
  *
  *     RETURNS:
  *     Zero on success, non-zero on error.
@@ -1207,8 +1352,7 @@
                ata_dev_identify(ap, i);
                if (ata_dev_present(&ap->device[i])) {
                        found = 1;
-                       if (ap->ops->dev_config)
-                               ap->ops->dev_config(ap, &ap->device[i]);
+                       ata_dev_config(ap,i);
                }
        }
 
@@ -1228,10 +1372,14 @@
 }
 
 /**
- *     ata_port_probe -
- *     @ap:
+ *     ata_port_probe - Mark port as enabled
+ *     @ap: Port for which we indicate enablement
  *
- *     LOCKING:
+ *     Modify @ap data structure such that the system
+ *     thinks that the entire port is enabled.
+ *
+ *     LOCKING: host_set lock, or some other form of
+ *     serialization.
  */
 
 void ata_port_probe(struct ata_port *ap)
@@ -1240,10 +1388,15 @@
 }
 
 /**
- *     __sata_phy_reset -
- *     @ap:
+ *     __sata_phy_reset - Wake/reset a low-level SATA PHY
+ *     @ap: SATA port associated with target SATA PHY.
+ *
+ *     This function issues commands to standard SATA Sxxx
+ *     PHY registers, to wake up the phy (and device), and
+ *     clear any reset condition.
  *
  *     LOCKING:
+ *     PCI/etc. bus probe sem.
  *
  */
 void __sata_phy_reset(struct ata_port *ap)
@@ -1252,11 +1405,13 @@
        unsigned long timeout = jiffies + (HZ * 5);
 
        if (ap->flags & ATA_FLAG_SATA_RESET) {
-               scr_write(ap, SCR_CONTROL, 0x301); /* issue phy wake/reset */
-               scr_read(ap, SCR_STATUS);       /* dummy read; flush */
-               udelay(400);                    /* FIXME: a guess */
+               /* issue phy wake/reset */
+               scr_write_flush(ap, SCR_CONTROL, 0x301);
+               /* Couldn't find anything in SATA I/II specs, but
+                * AHCI-1.1 10.4.2 says at least 1 ms. */
+               mdelay(1);
        }
-       scr_write(ap, SCR_CONTROL, 0x300);      /* issue phy wake/clear reset */
+       scr_write_flush(ap, SCR_CONTROL, 0x300); /* phy wake/clear reset */
 
        /* wait for phy to become ready, if necessary */
        do {
@@ -1288,10 +1443,14 @@
 }
 
 /**
- *     __sata_phy_reset -
- *     @ap:
+ *     sata_phy_reset - Reset SATA bus.
+ *     @ap: SATA port associated with target SATA PHY.
+ *
+ *     This function resets the SATA bus, and then probes
+ *     the bus for devices.
  *
  *     LOCKING:
+ *     PCI/etc. bus probe sem.
  *
  */
 void sata_phy_reset(struct ata_port *ap)
@@ -1303,10 +1462,16 @@
 }
 
 /**
- *     ata_port_disable -
- *     @ap:
+ *     ata_port_disable - Disable port.
+ *     @ap: Port to be disabled.
  *
- *     LOCKING:
+ *     Modify @ap data structure such that the system
+ *     thinks that the entire port is disabled, and should
+ *     never attempt to probe or communicate with devices
+ *     on this port.
+ *
+ *     LOCKING: host_set lock, or some other form of
+ *     serialization.
  */
 
 void ata_port_disable(struct ata_port *ap)
@@ -1415,7 +1580,10 @@
  *     ata_set_mode - Program timings and issue SET FEATURES - XFER
  *     @ap: port on which timings will be programmed
  *
+ *     Set ATA device disk transfer mode (PIO3, UDMA6, etc.).
+ *
  *     LOCKING:
+ *     PCI/etc. bus probe sem.
  *
  */
 static void ata_set_mode(struct ata_port *ap)
@@ -1466,7 +1634,10 @@
  *     @tmout_pat: impatience timeout
  *     @tmout: overall timeout
  *
- *     LOCKING:
+ *     Sleep until ATA Status register bit BSY clears,
+ *     or a timeout occurs.
+ *
+ *     LOCKING: None.
  *
  */
 
@@ -1552,10 +1723,14 @@
 }
 
 /**
- *     ata_bus_edd -
- *     @ap:
+ *     ata_bus_edd - Issue EXECUTE DEVICE DIAGNOSTIC command.
+ *     @ap: Port to reset and probe
+ *
+ *     Use the EXECUTE DEVICE DIAGNOSTIC command to reset and
+ *     probe the bus.  Not often used these days.
  *
  *     LOCKING:
+ *     PCI/etc. bus probe sem.
  *
  */
 
@@ -1632,8 +1807,8 @@
  *     the device is ATA or ATAPI.
  *
  *     LOCKING:
- *     Inherited from caller.  Some functions called by this function
- *     obtain the host_set lock.
+ *     PCI/etc. bus probe sem.
+ *     Obtains host_set lock.
  *
  *     SIDE EFFECTS:
  *     Sets ATA_FLAG_PORT_DISABLED if bus reset fails.
@@ -1746,6 +1921,7 @@
        "HITACHI CDR-8335",
        "HITACHI CDR-8435",
        "Toshiba CD-ROM XM-6202B",
+       "TOSHIBA CD-ROM XM-1702BC",
        "CD-532E-A",
        "E-IDE CD-ROM CR-840",
        "CD-ROM Drive/F5A",
@@ -1753,7 +1929,6 @@
        "SAMSUNG CD-ROM SC-148C",
        "SAMSUNG CD-ROM SC",
        "SanDisk SDP3B-64",
-       "SAMSUNG CD-ROM SN-124",
        "ATAPI CD-ROM DRIVE 40X MAXIMUM",
        "_NEC DV5800A",
 };
@@ -1875,7 +2050,11 @@
  *     @xfer_mode_out: (output) SET FEATURES - XFER MODE code
  *     @xfer_shift_out: (output) bit shift that selects this mode
  *
+ *     Based on host and device capabilities, determine the
+ *     maximum transfer mode that is amenable to all.
+ *
  *     LOCKING:
+ *     PCI/etc. bus probe sem.
  *
  *     RETURNS:
  *     Zero on success, negative on error.
@@ -1908,7 +2087,11 @@
  *     @ap: Port associated with device @dev
  *     @dev: Device to which command will be sent
  *
+ *     Issue SET FEATURES - XFER MODE command to device @dev
+ *     on port @ap.
+ *
  *     LOCKING:
+ *     PCI/etc. bus probe sem.
  */
 
 static void ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev)
@@ -1946,10 +2129,13 @@
 }
 
 /**
- *     ata_sg_clean -
- *     @qc:
+ *     ata_sg_clean - Unmap DMA memory associated with command
+ *     @qc: Command containing DMA memory to be released
+ *
+ *     Unmap all mapped DMA memory associated with this command.
  *
  *     LOCKING:
+ *     spin_lock_irqsave(host_set lock)
  */
 
 static void ata_sg_clean(struct ata_queued_cmd *qc)
@@ -1980,7 +2166,11 @@
  *     ata_fill_sg - Fill PCI IDE PRD table
  *     @qc: Metadata associated with taskfile to be transferred
  *
+ *     Fill PCI IDE PRD (scatter-gather) table with segments
+ *     associated with the current disk command.
+ *
  *     LOCKING:
+ *     spin_lock_irqsave(host_set lock)
  *
  */
 static void ata_fill_sg(struct ata_queued_cmd *qc)
@@ -2027,7 +2217,13 @@
  *     ata_check_atapi_dma - Check whether ATAPI DMA can be supported
  *     @qc: Metadata associated with taskfile to check
  *
+ *     Allow low-level driver to filter ATA PACKET commands, returning
+ *     a status indicating whether or not it is OK to use DMA for the
+ *     supplied PACKET command.
+ *
  *     LOCKING:
+ *     spin_lock_irqsave(host_set lock)
+ *
  *     RETURNS: 0 when ATAPI DMA can be used
  *               nonzero otherwise
  */
@@ -2045,6 +2241,8 @@
  *     ata_qc_prep - Prepare taskfile for submission
  *     @qc: Metadata associated with taskfile to be prepared
  *
+ *     Prepare ATA taskfile for submission.
+ *
  *     LOCKING:
  *     spin_lock_irqsave(host_set lock)
  */
@@ -2056,6 +2254,32 @@
        ata_fill_sg(qc);
 }
 
+/**
+ *     ata_sg_init_one - Associate command with memory buffer
+ *     @qc: Command to be associated
+ *     @buf: Memory buffer
+ *     @buflen: Length of memory buffer, in bytes.
+ *
+ *     Initialize the data-related elements of queued_cmd @qc
+ *     to point to a single memory buffer, @buf of byte length @buflen.
+ *
+ *     LOCKING:
+ *     spin_lock_irqsave(host_set lock)
+ */
+
+
+
+/**
+ *     ata_sg_init_one - Prepare a one-entry scatter-gather list.
+ *     @qc:  Queued command
+ *     @buf:  transfer buffer
+ *     @buflen:  length of buf
+ *
+ *     Builds a single-entry scatter-gather list to initiate a
+ *     transfer utilizing the specified buffer.
+ *
+ *     LOCKING:
+ */
 void ata_sg_init_one(struct ata_queued_cmd *qc, void *buf, unsigned int buflen)
 {
        struct scatterlist *sg;
@@ -2070,9 +2294,35 @@
        sg = qc->sg;
        sg->page = virt_to_page(buf);
        sg->offset = (unsigned long) buf & ~PAGE_MASK;
-       sg_dma_len(sg) = buflen;
+       sg->length = buflen;
 }
 
+/**
+ *     ata_sg_init - Associate command with scatter-gather table.
+ *     @qc: Command to be associated
+ *     @sg: Scatter-gather table.
+ *     @n_elem: Number of elements in s/g table.
+ *
+ *     Initialize the data-related elements of queued_cmd @qc
+ *     to point to a scatter-gather table @sg, containing @n_elem
+ *     elements.
+ *
+ *     LOCKING:
+ *     spin_lock_irqsave(host_set lock)
+ */
+
+
+/**
+ *     ata_sg_init - Assign a scatter gather list to a queued command
+ *     @qc:  Queued command
+ *     @sg:  Scatter-gather list
+ *     @n_elem:  length of sg list
+ *
+ *     Attaches a scatter-gather list to a queued command.
+ *
+ *     LOCKING:
+ */
+
 void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg,
                 unsigned int n_elem)
 {
@@ -2082,14 +2332,16 @@
 }
 
 /**
- *     ata_sg_setup_one -
- *     @qc:
+ *     ata_sg_setup_one - DMA-map the memory buffer associated with a command.
+ *     @qc: Command with memory buffer to be mapped.
+ *
+ *     DMA-map the memory buffer associated with queued_cmd @qc.
  *
  *     LOCKING:
  *     spin_lock_irqsave(host_set lock)
  *
  *     RETURNS:
- *
+ *     Zero on success, negative on error.
  */
 
 static int ata_sg_setup_one(struct ata_queued_cmd *qc)
@@ -2100,11 +2352,12 @@
        dma_addr_t dma_address;
 
        dma_address = dma_map_single(ap->host_set->dev, qc->buf_virt,
-                                    sg_dma_len(sg), dir);
+                                    sg->length, dir);
        if (dma_mapping_error(dma_address))
                return -1;
 
        sg_dma_address(sg) = dma_address;
+       sg_dma_len(sg) = sg->length;
 
        DPRINTK("mapped buffer of %d bytes for %s\n", sg_dma_len(sg),
                qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read");
@@ -2113,13 +2366,16 @@
 }
 
 /**
- *     ata_sg_setup -
- *     @qc:
+ *     ata_sg_setup - DMA-map the scatter-gather table associated with a 
command.
+ *     @qc: Command with scatter-gather table to be mapped.
+ *
+ *     DMA-map the scatter-gather table associated with queued_cmd @qc.
  *
  *     LOCKING:
  *     spin_lock_irqsave(host_set lock)
  *
  *     RETURNS:
+ *     Zero on success, negative on error.
  *
  */
 
@@ -2149,6 +2405,7 @@
  *     @ap:
  *
  *     LOCKING:
+ *     None.  (executing in kernel thread context)
  *
  *     RETURNS:
  *
@@ -2196,6 +2453,7 @@
  *     @ap:
  *
  *     LOCKING:
+ *     None.  (executing in kernel thread context)
  */
 
 static void ata_pio_complete (struct ata_port *ap)
@@ -2238,6 +2496,18 @@
        ata_qc_complete(qc, drv_stat);
 }
 
+
+/**
+ *     swap_buf_le16 -
+ *     @buf:  Buffer to swap
+ *     @buf_words:  Number of 16-bit words in buffer.
+ *
+ *     Swap halves of 16-bit words if needed to convert from
+ *     little-endian byte order to native cpu byte order, or
+ *     vice-versa.
+ *
+ *     LOCKING:
+ */
 void swap_buf_le16(u16 *buf, unsigned int buf_words)
 {
 #ifdef __BIG_ENDIAN
@@ -2309,7 +2579,7 @@
        qc->cursect++;
        qc->cursg_ofs++;
 
-       if ((qc->cursg_ofs * ATA_SECT_SIZE) == sg_dma_len(&sg[qc->cursg])) {
+       if ((qc->cursg_ofs * ATA_SECT_SIZE) == (&sg[qc->cursg])->length) {
                qc->cursg++;
                qc->cursg_ofs = 0;
        }
@@ -2338,7 +2608,6 @@
 next_sg:
        sg = &qc->sg[qc->cursg];
 
-next_page:
        page = sg->page;
        offset = sg->offset + qc->cursg_ofs;
 
@@ -2346,7 +2615,8 @@
        page = nth_page(page, (offset >> PAGE_SHIFT));
        offset %= PAGE_SIZE;
 
-       count = min(sg_dma_len(sg) - qc->cursg_ofs, bytes);
+       /* don't overrun current sg */
+       count = min(sg->length - qc->cursg_ofs, bytes);
 
        /* don't cross page boundaries */
        count = min(count, (unsigned int)PAGE_SIZE - offset);
@@ -2357,7 +2627,7 @@
        qc->curbytes += count;
        qc->cursg_ofs += count;
 
-       if (qc->cursg_ofs == sg_dma_len(sg)) {
+       if (qc->cursg_ofs == sg->length) {
                qc->cursg++;
                qc->cursg_ofs = 0;
        }
@@ -2370,8 +2640,6 @@
        kunmap(page);
 
        if (bytes) {
-               if (qc->cursg_ofs < sg_dma_len(sg))
-                       goto next_page;
                goto next_sg;
        }
 }
@@ -2413,6 +2681,7 @@
  *     @ap:
  *
  *     LOCKING:
+ *     None.  (executing in kernel thread context)
  */
 
 static void ata_pio_block(struct ata_port *ap)
@@ -2539,7 +2808,7 @@
        ata_sg_init_one(qc, cmd->sense_buffer, sizeof(cmd->sense_buffer));
        qc->dma_dir = DMA_FROM_DEVICE;
 
-       memset(&qc->cdb, 0, sizeof(ap->cdb_len));
+       memset(&qc->cdb, 0, ap->cdb_len);
        qc->cdb[0] = REQUEST_SENSE;
        qc->cdb[4] = SCSI_SENSE_BUFFERSIZE;
 
@@ -2582,6 +2851,7 @@
  *     transaction completed successfully.
  *
  *     LOCKING:
+ *     Inherited from SCSI layer (none, can sleep)
  */
 
 static void ata_qc_timeout(struct ata_queued_cmd *qc)
@@ -2691,6 +2961,7 @@
  *     @dev: Device from whom we request an available command structure
  *
  *     LOCKING:
+ *     None.
  */
 
 static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap)
@@ -2716,6 +2987,7 @@
  *     @dev: Device from whom we request an available command structure
  *
  *     LOCKING:
+ *     None.
  */
 
 struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap,
@@ -2780,6 +3052,7 @@
  *     in case something prevents using it.
  *
  *     LOCKING:
+ *     spin_lock_irqsave(host_set lock)
  *
  */
 void ata_qc_free(struct ata_queued_cmd *qc)
@@ -2793,9 +3066,13 @@
 /**
  *     ata_qc_complete - Complete an active ATA command
  *     @qc: Command to complete
- *     @drv_stat: ATA status register contents
+ *     @drv_stat: ATA Status register contents
+ *
+ *     Indicate to the mid and upper layers that an ATA
+ *     command has completed, with either an ok or not-ok status.
  *
  *     LOCKING:
+ *     spin_lock_irqsave(host_set lock)
  *
  */
 
@@ -2811,6 +3088,7 @@
 
        /* call completion callback */
        rc = qc->complete_fn(qc, drv_stat);
+       qc->flags &= ~ATA_QCFLAG_ACTIVE;
 
        /* if callback indicates not to complete command (non-zero),
         * return immediately
@@ -2839,7 +3117,7 @@
                        return 1;
 
                /* fall through */
-       
+
        default:
                return 0;
        }
@@ -2890,6 +3168,7 @@
        return -1;
 }
 
+
 /**
  *     ata_qc_issue_prot - issue taskfile to device in proto-dependent manner
  *     @qc: command to issue to device
@@ -2899,6 +3178,8 @@
  *     classes called "protocols", and issuing each type of protocol
  *     is slightly different.
  *
+ *     May be used as the qc_issue() entry in ata_port_operations.
+ *
  *     LOCKING:
  *     spin_lock_irqsave(host_set lock)
  *
@@ -2956,7 +3237,7 @@
 }
 
 /**
- *     ata_bmdma_setup - Set up PCI IDE BMDMA transaction
+ *     ata_bmdma_setup_mmio - Set up PCI IDE BMDMA transaction
  *     @qc: Info associated with this ATA transaction.
  *
  *     LOCKING:
@@ -3063,6 +3344,18 @@
             ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
 }
 
+
+/**
+ *     ata_bmdma_start - Start a PCI IDE BMDMA transaction
+ *     @qc: Info associated with this ATA transaction.
+ *
+ *     Writes the ATA_DMA_START flag to the DMA command register.
+ *
+ *     May be used as the bmdma_start() entry in ata_port_operations.
+ *
+ *     LOCKING:
+ *     spin_lock_irqsave(host_set lock)
+ */
 void ata_bmdma_start(struct ata_queued_cmd *qc)
 {
        if (qc->ap->flags & ATA_FLAG_MMIO)
@@ -3071,6 +3364,20 @@
                ata_bmdma_start_pio(qc);
 }
 
+
+/**
+ *     ata_bmdma_setup - Set up PCI IDE BMDMA transaction
+ *     @qc: Info associated with this ATA transaction.
+ *
+ *     Writes address of PRD table to device's PRD Table Address
+ *     register, sets the DMA control register, and calls
+ *     ops->exec_command() to start the transfer.
+ *
+ *     May be used as the bmdma_setup() entry in ata_port_operations.
+ *
+ *     LOCKING:
+ *     spin_lock_irqsave(host_set lock)
+ */
 void ata_bmdma_setup(struct ata_queued_cmd *qc)
 {
        if (qc->ap->flags & ATA_FLAG_MMIO)
@@ -3079,6 +3386,19 @@
                ata_bmdma_setup_pio(qc);
 }
 
+
+/**
+ *     ata_bmdma_irq_clear - Clear PCI IDE BMDMA interrupt.
+ *     @ap: Port associated with this ATA transaction.
+ *
+ *     Clear interrupt and error flags in DMA status register.
+ *
+ *     May be used as the irq_clear() entry in ata_port_operations.
+ *
+ *     LOCKING:
+ *     spin_lock_irqsave(host_set lock)
+ */
+
 void ata_bmdma_irq_clear(struct ata_port *ap)
 {
     if (ap->flags & ATA_FLAG_MMIO) {
@@ -3091,6 +3411,19 @@
 
 }
 
+
+/**
+ *     ata_bmdma_status - Read PCI IDE BMDMA status
+ *     @ap: Port associated with this ATA transaction.
+ *
+ *     Read and return BMDMA status register.
+ *
+ *     May be used as the bmdma_status() entry in ata_port_operations.
+ *
+ *     LOCKING:
+ *     spin_lock_irqsave(host_set lock)
+ */
+
 u8 ata_bmdma_status(struct ata_port *ap)
 {
        u8 host_stat;
@@ -3102,6 +3435,19 @@
        return host_stat;
 }
 
+
+/**
+ *     ata_bmdma_stop - Stop PCI IDE BMDMA transfer
+ *     @ap: Port associated with this ATA transaction.
+ *
+ *     Clears the ATA_DMA_START flag in the dma control register
+ *
+ *     May be used as the bmdma_stop() entry in ata_port_operations.
+ *
+ *     LOCKING:
+ *     spin_lock_irqsave(host_set lock)
+ */
+
 void ata_bmdma_stop(struct ata_port *ap)
 {
        if (ap->flags & ATA_FLAG_MMIO) {
@@ -3201,13 +3547,18 @@
 
 /**
  *     ata_interrupt - Default ATA host interrupt handler
- *     @irq: irq line
- *     @dev_instance: pointer to our host information structure
+ *     @irq: irq line (unused)
+ *     @dev_instance: pointer to our ata_host_set information structure
  *     @regs: unused
  *
+ *     Default interrupt handler for PCI IDE devices.  Calls
+ *     ata_host_intr() for each port that is not disabled.
+ *
  *     LOCKING:
+ *     Obtains host_set lock during operation.
  *
  *     RETURNS:
+ *     IRQ_NONE or IRQ_HANDLED.
  *
  */
 
@@ -3229,7 +3580,8 @@
                        struct ata_queued_cmd *qc;
 
                        qc = ata_qc_from_tag(ap, ap->active_tag);
-                       if (qc && (!(qc->tf.ctl & ATA_NIEN)))
+                       if (qc && (!(qc->tf.ctl & ATA_NIEN)) &&
+                           (qc->flags & ATA_QCFLAG_ACTIVE))
                                handled |= ata_host_intr(ap, qc);
                }
        }
@@ -3299,6 +3651,19 @@
        ata_qc_complete(qc, ATA_ERR);
 }
 
+
+/**
+ *     ata_port_start - Set port up for dma.
+ *     @ap: Port to initialize
+ *
+ *     Called just after data structures for each port are
+ *     initialized.  Allocates space for PRD table.
+ *
+ *     May be used as the port_start() entry in ata_port_operations.
+ *
+ *     LOCKING:
+ */
+
 int ata_port_start (struct ata_port *ap)
 {
        struct device *dev = ap->host_set->dev;
@@ -3312,6 +3677,18 @@
        return 0;
 }
 
+
+/**
+ *     ata_port_stop - Undo ata_port_start()
+ *     @ap: Port to shut down
+ *
+ *     Frees the PRD table.
+ *
+ *     May be used as the port_stop() entry in ata_port_operations.
+ *
+ *     LOCKING:
+ */
+
 void ata_port_stop (struct ata_port *ap)
 {
        struct device *dev = ap->host_set->dev;
@@ -3319,6 +3696,13 @@
        dma_free_coherent(dev, ATA_PRD_TBL_SZ, ap->prd, ap->prd_dma);
 }
 
+void ata_host_stop (struct ata_host_set *host_set)
+{
+       if (host_set->mmio_base)
+               iounmap(host_set->mmio_base);
+}
+
+
 /**
  *     ata_host_remove - Unregister SCSI host structure with upper layers
  *     @ap: Port to unregister
@@ -3347,7 +3731,11 @@
  *     @ent: Probe information provided by low-level driver
  *     @port_no: Port number associated with this ata_port
  *
+ *     Initialize a new ata_port structure, and its associated
+ *     scsi_host.
+ *
  *     LOCKING:
+ *     Inherited from caller.
  *
  */
 
@@ -3401,9 +3789,13 @@
  *     @host_set: Collections of ports to which we add
  *     @port_no: Port number associated with this host
  *
+ *     Attach low-level ATA driver to system.
+ *
  *     LOCKING:
+ *     PCI/etc. bus probe sem.
  *
  *     RETURNS:
+ *     New ata_port on success, for NULL on error.
  *
  */
 
@@ -3436,12 +3828,22 @@
 }
 
 /**
- *     ata_device_add -
- *     @ent:
+ *     ata_device_add - Register hardware device with ATA and SCSI layers
+ *     @ent: Probe information describing hardware device to be registered
+ *
+ *     This function processes the information provided in the probe
+ *     information struct @ent, allocates the necessary ATA and SCSI
+ *     host information structures, initializes them, and registers
+ *     everything with requisite kernel subsystems.
+ *
+ *     This function requests irqs, probes the ATA bus, and probes
+ *     the SCSI bus.
  *
  *     LOCKING:
+ *     PCI/etc. bus probe sem.
  *
  *     RETURNS:
+ *     Number of ports registered.  Zero on error (no ports registered).
  *
  */
 
@@ -3612,7 +4014,15 @@
 /**
  *     ata_std_ports - initialize ioaddr with standard port offsets.
  *     @ioaddr: IO address structure to be initialized
+ *
+ *     Utility function which initializes data_addr, error_addr,
+ *     feature_addr, nsect_addr, lbal_addr, lbam_addr, lbah_addr,
+ *     device_addr, status_addr, and command_addr to standard offsets
+ *     relative to cmd_addr.
+ *
+ *     Does not set ctl_addr, altstatus_addr, bmdma_addr, or scr_addr.
  */
+
 void ata_std_ports(struct ata_ioports *ioaddr)
 {
        ioaddr->data_addr = ioaddr->cmd_addr + ATA_REG_DATA;
@@ -3654,6 +4064,20 @@
        return probe_ent;
 }
 
+
+
+/**
+ *     ata_pci_init_native_mode - Initialize native-mode driver
+ *     @pdev:  pci device to be initialized
+ *     @port:  array[2] of pointers to port info structures.
+ *
+ *     Utility function which allocates and initializes an
+ *     ata_probe_ent structure for a standard dual-port
+ *     PIO-based IDE controller.  The returned ata_probe_ent
+ *     structure can be passed to ata_device_add().  The returned
+ *     ata_probe_ent structure should then be freed with kfree().
+ */
+
 #ifdef CONFIG_PCI
 struct ata_probe_ent *
 ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port)
@@ -3735,10 +4159,19 @@
  *     @port_info: Information from low-level host driver
  *     @n_ports: Number of ports attached to host controller
  *
+ *     This is a helper function which can be called from a driver's
+ *     xxx_init_one() probe function if the hardware uses traditional
+ *     IDE taskfile registers.
+ *
+ *     This function calls pci_enable_device(), reserves its register
+ *     regions, sets the dma mask, enables bus master mode, and calls
+ *     ata_device_add()
+ *
  *     LOCKING:
  *     Inherited from PCI layer (may sleep).
  *
  *     RETURNS:
+ *     Zero on success, negative on errno-based value on error.
  *
  */
 
@@ -3882,10 +4315,6 @@
        /* FIXME: handle 'rc' failure? */
 
        free_irq(host_set->irq, host_set);
-       if (host_set->ops->host_stop)
-               host_set->ops->host_stop(host_set);
-       if (host_set->mmio_base)
-               iounmap(host_set->mmio_base);
 
        for (i = 0; i < host_set->n_ports; i++) {
                ap = host_set->ports[i];
@@ -3900,6 +4329,9 @@
                }
        }
 
+       if (host_set->ops->host_stop)
+               host_set->ops->host_stop(host_set);
+
        kfree(host_set);
 
        pci_release_regions(pdev);
@@ -3958,15 +4390,6 @@
 #endif /* CONFIG_PCI */
 
 
-/**
- *     ata_init -
- *
- *     LOCKING:
- *
- *     RETURNS:
- *
- */
-
 static int __init ata_init(void)
 {
        printk(KERN_DEBUG "libata version " DRV_VERSION " loaded.\n");
@@ -4007,6 +4430,7 @@
 EXPORT_SYMBOL_GPL(ata_exec_command);
 EXPORT_SYMBOL_GPL(ata_port_start);
 EXPORT_SYMBOL_GPL(ata_port_stop);
+EXPORT_SYMBOL_GPL(ata_host_stop);
 EXPORT_SYMBOL_GPL(ata_interrupt);
 EXPORT_SYMBOL_GPL(ata_qc_prep);
 EXPORT_SYMBOL_GPL(ata_bmdma_setup);
@@ -4029,6 +4453,7 @@
 EXPORT_SYMBOL_GPL(ata_host_intr);
 EXPORT_SYMBOL_GPL(ata_dev_classify);
 EXPORT_SYMBOL_GPL(ata_dev_id_string);
+EXPORT_SYMBOL_GPL(ata_dev_config);
 EXPORT_SYMBOL_GPL(ata_scsi_simulate);
 
 #ifdef CONFIG_PCI
diff -urN linux/drivers/scsi/libata-scsi.c linux/drivers/scsi/libata-scsi.c
--- linux/drivers/scsi/libata-scsi.c    2005/05/23 12:12:31     1.10.2.7
+++ linux/drivers/scsi/libata-scsi.c    2005/09/23 20:41:23     1.10.2.8
@@ -906,7 +906,7 @@
 }
 
 /**
- *     ata_scsiop_noop -
+ *     ata_scsiop_noop - Command handler that simply returns success.
  *     @args: device IDENTIFY data / SCSI command of interest.
  *     @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
  *     @buflen: Response buffer length.
@@ -1135,8 +1135,12 @@
                n_sectors = ata_id_u32(args->id, 60);
        n_sectors--;            /* ATA TotalUserSectors - 1 */
 
-       tmp = n_sectors;        /* note: truncates, if lba48 */
        if (args->cmd->cmnd[0] == READ_CAPACITY) {
+               if( n_sectors >= 0xffffffffULL )
+                       tmp = 0xffffffff ;  /* Return max count on overflow */
+               else
+                       tmp = n_sectors ;
+
                /* sector count, 32-bit */
                rbuf[0] = tmp >> (8 * 3);
                rbuf[1] = tmp >> (8 * 2);
@@ -1150,10 +1154,12 @@
 
        } else {
                /* sector count, 64-bit */
-               rbuf[2] = n_sectors >> (8 * 7);
-               rbuf[3] = n_sectors >> (8 * 6);
-               rbuf[4] = n_sectors >> (8 * 5);
-               rbuf[5] = n_sectors >> (8 * 4);
+               tmp = n_sectors >> (8 * 4);
+               rbuf[2] = tmp >> (8 * 3);
+               rbuf[3] = tmp >> (8 * 2);
+               rbuf[4] = tmp >> (8 * 1);
+               rbuf[5] = tmp;
+               tmp = n_sectors;
                rbuf[6] = tmp >> (8 * 3);
                rbuf[7] = tmp >> (8 * 2);
                rbuf[8] = tmp >> (8 * 1);
diff -urN linux/drivers/scsi/libata.h linux/drivers/scsi/libata.h
--- linux/drivers/scsi/libata.h 2005/03/18 12:13:27     1.9.2.5
+++ linux/drivers/scsi/libata.h 2005/09/23 20:41:23     1.9.2.6
@@ -26,7 +26,7 @@
 #define __LIBATA_H__
 
 #define DRV_NAME       "libata"
-#define DRV_VERSION    "1.10"  /* must be exactly four chars */
+#define DRV_VERSION    "1.11"  /* must be exactly four chars */
 
 struct ata_scsi_args {
        u16                     *id;
diff -urN linux/drivers/scsi/megaraid2.c linux/drivers/scsi/megaraid2.c
--- linux/drivers/scsi/Attic/megaraid2.c        2005/03/18 12:13:27     1.1.2.6
+++ linux/drivers/scsi/Attic/megaraid2.c        2005/09/23 20:41:23     1.1.2.7
@@ -14,7 +14,7 @@
  *       - speed-ups (list handling fixes, issued_list, optimizations.)
  *       - lots of cleanups.
  *
- * Version : v2.10.8.2 (July 26, 2004)
+ * Version : v2.10.10.1 (January 27, 2005)
  *
  * Authors:    Atul Mukker <Atul.Mukker@lsil.com>
  *             Sreenivas Bagalkote <Sreenivas.Bagalkote@lsil.com>
@@ -46,7 +46,7 @@
 
 #include "megaraid2.h"
 
-#if defined(__x86_64__)
+#ifdef LSI_CONFIG_COMPAT
 #include <asm/ioctl32.h>
 #endif
 
@@ -181,7 +181,7 @@
        /*
         * Scan PCI bus for our all devices.
         */
-       for( i = 0; i < sizeof(dev_sw_table)/sizeof(u16); i += 2 ) {
+       for( i = 0; i < ((int) (sizeof(dev_sw_table)/sizeof(u16))); i += 2 ) {
 
                mega_find_card(host_template, dev_sw_table[i],
                                dev_sw_table[i+1]);
@@ -233,7 +233,7 @@
                                "MegaRAID Shutdown routine not registered!!\n");
                }
 
-#if defined(__x86_64__)
+#ifdef LSI_CONFIG_COMPAT
                /*
                 * Register the 32-bit ioctl conversion
                 */
@@ -341,6 +341,7 @@
                                (subsysvid != INTEL_SUBSYS_VID) &&
                                (subsysvid != FSC_SUBSYS_VID) &&
                                (subsysvid != ACER_SUBSYS_VID) &&
+                               (subsysvid != NEC_SUBSYS_VID) &&
                                (subsysvid != LSI_SUBSYS_VID) ) continue;
 
 
@@ -821,6 +822,78 @@
 }
 
 
+/**
+ * issue_scb()
+ * @adapter - pointer to our soft state
+ * @scb - scsi control block
+ *
+ * Post a command to the card if the mailbox is available, otherwise return
+ * busy. We also take the scb from the pending list if the mailbox is
+ * available.
+ */
+static inline int
+issue_scb(adapter_t *adapter, scb_t *scb)
+{
+       volatile mbox64_t       *mbox64 = adapter->mbox64;
+       volatile mbox_t         *mbox = adapter->mbox;
+       unsigned int    i = 0;
+
+       if(unlikely(mbox->busy)) {
+               do {
+                       udelay(1);
+                       i++;
+               } while( mbox->busy && (i < max_mbox_busy_wait) );
+
+               if(mbox->busy) return -1;
+       }
+
+       /* Copy mailbox data into host structure */
+       memcpy((char *)mbox, (char *)scb->raw_mbox, 16);
+
+       mbox->cmdid = scb->idx; /* Set cmdid */
+       mbox->busy = 1;         /* Set busy */
+
+
+       /*
+        * Increment the pending queue counter
+        */
+       atomic_inc(&adapter->pend_cmds);
+
+       switch (mbox->cmd) {
+       case MEGA_MBOXCMD_EXTPTHRU:
+               if( !adapter->has_64bit_addr ) break;
+               // else fall through
+       case MEGA_MBOXCMD_LREAD64:
+       case MEGA_MBOXCMD_LWRITE64:
+       case MEGA_MBOXCMD_PASSTHRU64:
+               mbox64->xfer_segment_lo = mbox->xferaddr;
+               mbox64->xfer_segment_hi = 0;
+               mbox->xferaddr = 0xFFFFFFFF;
+               break;
+       default:
+               mbox64->xfer_segment_lo = 0;
+               mbox64->xfer_segment_hi = 0;
+       }
+
+       /*
+        * post the command
+        */
+       scb->state |= SCB_ISSUED;
+
+       if( likely(adapter->flag & BOARD_MEMMAP) ) {
+               mbox->poll = 0;
+               mbox->ack = 0;
+               WRINDOOR(adapter, adapter->mbox_dma | 0x1);
+       }
+       else {
+               irq_enable(adapter);
+               issue_command(adapter);
+       }
+
+       return 0;
+}
+
+
 /*
  * mega_query_adapter()
  * @adapter - pointer to our soft state
@@ -990,78 +1063,6 @@
 
 
 /**
- * issue_scb()
- * @adapter - pointer to our soft state
- * @scb - scsi control block
- *
- * Post a command to the card if the mailbox is available, otherwise return
- * busy. We also take the scb from the pending list if the mailbox is
- * available.
- */
-static inline int
-issue_scb(adapter_t *adapter, scb_t *scb)
-{
-       volatile mbox64_t       *mbox64 = adapter->mbox64;
-       volatile mbox_t         *mbox = adapter->mbox;
-       unsigned int    i = 0;
-
-       if(unlikely(mbox->busy)) {
-               do {
-                       udelay(1);
-                       i++;
-               } while( mbox->busy && (i < max_mbox_busy_wait) );
-
-               if(mbox->busy) return -1;
-       }
-
-       /* Copy mailbox data into host structure */
-       memcpy((char *)mbox, (char *)scb->raw_mbox, 16);
-
-       mbox->cmdid = scb->idx; /* Set cmdid */
-       mbox->busy = 1;         /* Set busy */
-
-
-       /*
-        * Increment the pending queue counter
-        */
-       atomic_inc(&adapter->pend_cmds);
-
-       switch (mbox->cmd) {
-       case MEGA_MBOXCMD_EXTPTHRU:
-               if( !adapter->has_64bit_addr ) break;
-               // else fall through
-       case MEGA_MBOXCMD_LREAD64:
-       case MEGA_MBOXCMD_LWRITE64:
-       case MEGA_MBOXCMD_PASSTHRU64:
-               mbox64->xfer_segment_lo = mbox->xferaddr;
-               mbox64->xfer_segment_hi = 0;
-               mbox->xferaddr = 0xFFFFFFFF;
-               break;
-       default:
-               mbox64->xfer_segment_lo = 0;
-               mbox64->xfer_segment_hi = 0;
-       }
-
-       /*
-        * post the command
-        */
-       scb->state |= SCB_ISSUED;
-
-       if( likely(adapter->flag & BOARD_MEMMAP) ) {
-               mbox->poll = 0;
-               mbox->ack = 0;
-               WRINDOOR(adapter, adapter->mbox_dma | 0x1);
-       }
-       else {
-               irq_enable(adapter);
-               issue_command(adapter);
-       }
-
-       return 0;
-}
-
-
-/**
  * mega_runpendq()
  * @adapter - pointer to our soft state
  *
@@ -1074,7 +1075,6 @@
                __mega_runpendq(adapter);
 }
 
-
 static void
 __mega_runpendq(adapter_t *adapter)
 {
@@ -1176,80 +1176,6 @@
        return ldrv_num;
 }
 
-/*
- * Wait until the controller's mailbox is available
- */
-static inline int
-mega_busywait_mbox (adapter_t *adapter)
-{
-       if (adapter->mbox->busy)
-               return __mega_busywait_mbox(adapter);
-       return 0;
-}
-
-
-/**
- * megaraid_iombox_ack_sequence - interrupt ack sequence for IO mapped HBAs
- * @adapter    - controller's soft state
- *
- * Interrupt ackrowledgement sequence for IO mapped HBAs
- */
-static inline void
-megaraid_iombox_ack_sequence(adapter_t *adapter)
-{
-       u8      status;
-       u8      nstatus;
-       u8      completed[MAX_FIRMWARE_STATUS];
-       u8      byte;
-       int     i;
-
-
-       /*
-        * loop till F/W has more commands for us to complete.
-        */
-       do {
-               /* Check if a valid interrupt is pending */
-               byte = irq_state(adapter);
-               if( (byte & VALID_INTR_BYTE) == 0 ) {
-                       return;
-               }
-               set_irq_state(adapter, byte);
-
-               while ((nstatus = adapter->mbox->numstatus) == 0xFF) {
-                       cpu_relax();
-               }
-               adapter->mbox->numstatus = 0xFF;
-
-               for (i = 0; i < nstatus; i++) {
-                       while ((completed[i] = adapter->mbox->completed[i])
-                                       == 0xFF) {
-                               cpu_relax();
-                       }
-
-                       adapter->mbox->completed[i] = 0xFF;
-               }
-
-               // we must read the valid status now
-               if ((status = adapter->mbox->status) == 0xFF) {
-                       printk(KERN_WARNING
-                       "megaraid critical: status 0xFF from firmware.\n");
-               }
-               adapter->mbox->status = 0xFF;
-
-               /*
-                * decrement the pending queue counter
-                */
-               atomic_sub(nstatus, &adapter->pend_cmds);
-
-               /* Acknowledge interrupt */
-               irq_ack(adapter);
-
-               mega_cmd_done(adapter, completed, nstatus, status);
-
-       } while(1);
-}
-
-
 
 /*
  * megaraid_queue()
@@ -1755,8 +1681,8 @@
        pthru = scb->pthru;
        memset(pthru, 0, sizeof (mega_passthru));
 
-       /* 0=6sec/1=60sec/2=10min/3=3hrs */
-       pthru->timeout = 2;
+       /* 0=6sec/1=60sec/2=10min/3=3hrs/4=NO timeout */
+       pthru->timeout = 4;
 
        pthru->ars = 1;
        pthru->reqsenselen = 14;
@@ -1819,8 +1745,8 @@
        epthru = scb->epthru;
        memset(epthru, 0, sizeof(mega_ext_passthru));
 
-       /* 0=6sec/1=60sec/2=10min/3=3hrs */
-       epthru->timeout = 2;
+       /* 0=6sec/1=60sec/2=10min/3=3hrs/4=NO timeout */
+       epthru->timeout = 4;
 
        epthru->ars = 1;
        epthru->reqsenselen = 14;
@@ -1862,6 +1788,32 @@
 }
 
 
+/*
+ * Wait until the controller's mailbox is available
+ */
+static inline int
+mega_busywait_mbox (adapter_t *adapter)
+{
+       if (adapter->mbox->busy)
+               return __mega_busywait_mbox(adapter);
+       return 0;
+}
+
+static int
+__mega_busywait_mbox (adapter_t *adapter)
+{
+       volatile mbox_t *mbox = adapter->mbox;
+       long counter;
+
+       for (counter = 0; counter < 10000; counter++) {
+               if (!mbox->busy)
+                       return 0;
+               udelay(100); yield();
+       }
+       return -1;              /* give up after 1 second */
+}
+
+
 /**
  * issue_scb_block()
  * @adapter - pointer to our soft state
@@ -1962,137 +1914,7 @@
        return -1;
 }
 
-
-/**
- * megaraid_isr_iomapped()
- * @irq - irq
- * @devp - pointer to our soft state
- * @regs - unused
- *
- * Interrupt service routine for io-mapped controllers.
- * Find out if our device is interrupting. If yes, acknowledge the interrupt
- * and service the completed commands.
- */
-static void
-megaraid_isr_iomapped(int irq, void *devp, struct pt_regs *regs)
-{
-       adapter_t       *adapter = devp;
-       unsigned long   flags;
-
-
-       spin_lock_irqsave(adapter->host_lock, flags);
-
-       megaraid_iombox_ack_sequence(adapter);
-
-       /* Loop through any pending requests */
-       if( atomic_read(&adapter->quiescent ) == 0) {
-               mega_runpendq(adapter);
-       }
-
-       spin_unlock_irqrestore(adapter->host_lock, flags);
-
-       return;
-}
-
-
-/**
- * megaraid_memmbox_ack_sequence - interrupt ack sequence for memory mapped 
HBAs
- * @adapter    - controller's soft state
- *
- * Interrupt ackrowledgement sequence for memory mapped HBAs
- */
-static inline void
-megaraid_memmbox_ack_sequence(adapter_t *adapter)
-{
-       u8      status;
-       u32     dword = 0;
-       u8      nstatus;
-       u8      completed[MAX_FIRMWARE_STATUS];
-       int     i;
-
-
-       /*
-        * loop till F/W has more commands for us to complete.
-        */
-       do {
-               /* Check if a valid interrupt is pending */
-               dword = RDOUTDOOR(adapter);
-               if( dword != 0x10001234 ) {
-                       /*
-                        * No more pending commands
-                        */
-                       return;
-               }
-               WROUTDOOR(adapter, 0x10001234);
-
-               while ((nstatus = adapter->mbox->numstatus) == 0xFF) {
-                       cpu_relax();
-               }
-               adapter->mbox->numstatus = 0xFF;
-
-               for (i = 0; i < nstatus; i++ ) {
-                       while ((completed[i] = adapter->mbox->completed[i])
-                                       == 0xFF) {
-                               cpu_relax();
-                       }
-
-                       adapter->mbox->completed[i] = 0xFF;
-               }
-
-               // we must read the valid status now
-               if ((status = adapter->mbox->status) == 0xFF) {
-                       printk(KERN_WARNING
-                       "megaraid critical: status 0xFF from firmware.\n");
-               }
-               adapter->mbox->status = 0xFF;
-
-               /*
-                * decrement the pending queue counter
-                */
-               atomic_sub(nstatus, &adapter->pend_cmds);
-
-               /* Acknowledge interrupt */
-               WRINDOOR(adapter, 0x2);
-
-               while( RDINDOOR(adapter) & 0x02 ) cpu_relax();
-
-               mega_cmd_done(adapter, completed, nstatus, status);
-
-       } while(1);
-}
-
-
-/**
- * megaraid_isr_memmapped()
- * @irq - irq
- * @devp - pointer to our soft state
- * @regs - unused
- *
- * Interrupt service routine for memory-mapped controllers.
- * Find out if our device is interrupting. If yes, acknowledge the interrupt
- * and service the completed commands.
- */
-static void
-megaraid_isr_memmapped(int irq, void *devp, struct pt_regs *regs)
-{
-       adapter_t       *adapter = devp;
-       unsigned long   flags;
-
-
-       spin_lock_irqsave(adapter->host_lock, flags);
-
-       megaraid_memmbox_ack_sequence(adapter);
-
-       /* Loop through any pending requests */
-       if(atomic_read(&adapter->quiescent) == 0) {
-               mega_runpendq(adapter);
-       }
-
-       spin_unlock_irqrestore(adapter->host_lock, flags);
-
-       return;
-}
-
+
 /**
  * mega_cmd_done()
  * @adapter - pointer to our soft state
@@ -2102,7 +1924,7 @@
  *
  * Complete the comamnds and call the scsi mid-layer callback hooks.
  */
-static void
+static inline void
 mega_cmd_done(adapter_t *adapter, u8 completed[], int nstatus, int status)
 {
        mega_ext_passthru       *epthru = NULL;
@@ -2351,6 +2173,197 @@
 }
 
 
+/**
+ * megaraid_iombox_ack_sequence - interrupt ack sequence for IO mapped HBAs
+ * @adapter    - controller's soft state
+ *
+ * Interrupt ackrowledgement sequence for IO mapped HBAs
+ */
+static inline void
+megaraid_iombox_ack_sequence(adapter_t *adapter)
+{
+       u8      status;
+       int     nstatus;
+       u8      completed[MAX_FIRMWARE_STATUS];
+       u8      byte;
+       int     i;
+
+
+       /*
+        * loop till F/W has more commands for us to complete.
+        */
+       do {
+               /* Check if a valid interrupt is pending */
+               byte = irq_state(adapter);
+               if( (byte & VALID_INTR_BYTE) == 0 ) {
+                       return;
+               }
+               set_irq_state(adapter, byte);
+
+               while ((nstatus = adapter->mbox->numstatus) == 0xFF) {
+                       cpu_relax();
+               }
+               adapter->mbox->numstatus = 0xFF;
+
+               for (i = 0; i < nstatus; i++) {
+                       while ((completed[i] = adapter->mbox->completed[i])
+                                       == 0xFF) {
+                               cpu_relax();
+                       }
+
+                       adapter->mbox->completed[i] = 0xFF;
+               }
+
+               // we must read the valid status now
+               if ((status = adapter->mbox->status) == 0xFF) {
+                       printk(KERN_WARNING
+                       "megaraid critical: status 0xFF from firmware.\n");
+               }
+               adapter->mbox->status = 0xFF;
+
+               /*
+                * decrement the pending queue counter
+                */
+               atomic_sub(nstatus, &adapter->pend_cmds);
+
+               /* Acknowledge interrupt */
+               irq_ack(adapter);
+
+               mega_cmd_done(adapter, completed, nstatus, status);
+
+       } while(1);
+}
+
+
+/**
+ * megaraid_isr_iomapped()
+ * @irq - irq
+ * @devp - pointer to our soft state
+ * @regs - unused
+ *
+ * Interrupt service routine for io-mapped controllers.
+ * Find out if our device is interrupting. If yes, acknowledge the interrupt
+ * and service the completed commands.
+ */
+static void
+megaraid_isr_iomapped(int irq, void *devp, struct pt_regs *regs)
+{
+       adapter_t       *adapter = devp;
+       unsigned long   flags;
+
+       spin_lock_irqsave(adapter->host_lock, flags);
+
+       megaraid_iombox_ack_sequence(adapter);
+
+       /* Loop through any pending requests */
+       if( atomic_read(&adapter->quiescent ) == 0) {
+               mega_runpendq(adapter);
+       }
+
+       spin_unlock_irqrestore(adapter->host_lock, flags);
+
+       return;
+}
+
+
+/**
+ * megaraid_memmbox_ack_sequence - interrupt ack sequence for memory mapped 
HBAs
+ * @adapter    - controller's soft state
+ *
+ * Interrupt ackrowledgement sequence for memory mapped HBAs
+ */
+static inline void
+megaraid_memmbox_ack_sequence(adapter_t *adapter)
+{
+       u8      status;
+       u32     dword = 0;
+       int     nstatus;
+       u8      completed[MAX_FIRMWARE_STATUS];
+       int     i;
+
+
+       /*
+        * loop till F/W has more commands for us to complete.
+        */
+       do {
+               /* Check if a valid interrupt is pending */
+               dword = RDOUTDOOR(adapter);
+               if( dword != 0x10001234 ) {
+                       /*
+                        * No more pending commands
+                        */
+                       return;
+               }
+               WROUTDOOR(adapter, 0x10001234);
+
+               while ((nstatus = adapter->mbox->numstatus) == 0xFF) {
+                       cpu_relax();
+               }
+               adapter->mbox->numstatus = 0xFF;
+
+               for (i = 0; i < nstatus; i++ ) {
+                       while ((completed[i] = adapter->mbox->completed[i])
+                                       == 0xFF) {
+                               cpu_relax();
+                       }
+
+                       adapter->mbox->completed[i] = 0xFF;
+               }
+
+               // we must read the valid status now
+               if ((status = adapter->mbox->status) == 0xFF) {
+                       printk(KERN_WARNING
+                       "megaraid critical: status 0xFF from firmware.\n");
+               }
+               adapter->mbox->status = 0xFF;
+
+               /*
+                * decrement the pending queue counter
+                */
+               atomic_sub(nstatus, &adapter->pend_cmds);
+
+               /* Acknowledge interrupt */
+               WRINDOOR(adapter, 0x2);
+
+               while( RDINDOOR(adapter) & 0x02 ) cpu_relax();
+
+               mega_cmd_done(adapter, completed, nstatus, status);
+
+       } while(1);
+}
+
+
+/**
+ * megaraid_isr_memmapped()
+ * @irq - irq
+ * @devp - pointer to our soft state
+ * @regs - unused
+ *
+ * Interrupt service routine for memory-mapped controllers.
+ * Find out if our device is interrupting. If yes, acknowledge the interrupt
+ * and service the completed commands.
+ */
+static void
+megaraid_isr_memmapped(int irq, void *devp, struct pt_regs *regs)
+{
+       adapter_t       *adapter = devp;
+       unsigned long   flags;
+
+       spin_lock_irqsave(adapter->host_lock, flags);
+
+       megaraid_memmbox_ack_sequence(adapter);
+
+       /* Loop through any pending requests */
+       if(atomic_read(&adapter->quiescent) == 0) {
+               mega_runpendq(adapter);
+       }
+
+       spin_unlock_irqrestore(adapter->host_lock, flags);
+
+       return;
+}
+
+
 /*
  * Free a SCB structure
  * Note: We assume the scsi commands associated with this scb is not free yet.
@@ -2404,19 +2417,6 @@
        list_add(&scb->list, &adapter->free_list);
 }
 
-static int
-__mega_busywait_mbox (adapter_t *adapter)
-{
-       volatile mbox_t *mbox = adapter->mbox;
-       long counter;
-
-       for (counter = 0; counter < 10000; counter++) {
-               if (!mbox->busy)
-                       return 0;
-               udelay(100); yield();
-       }
-       return -1;              /* give up after 1 second */
-}
 
 /*
  * Copies data to SGLIST
@@ -2434,7 +2434,7 @@
 
        cmd = scb->cmd;
 
-       /* return 0 elements if no data transfer */
+       // return 0 elements if no data transfer
        if (!cmd->request_buffer || !cmd->request_bufflen)
                return 0;
 
@@ -2561,6 +2561,7 @@
                enquiry3->pdrv_state[i] = inquiry->pdrv_info.pdrv_state[i];
 }
 
+
 static inline void
 mega_free_sgl(adapter_t *adapter)
 {
@@ -2726,7 +2727,7 @@
         */
        scsi_unregister(host);
 
-#if defined(__x86_64__)
+#ifdef LSI_CONFIG_COMPAT
        unregister_ioctl32_conversion(MEGAIOCCMD);
 #endif
 
@@ -2835,7 +2836,6 @@
        return SUCCESS;
 }
 
-
 static int
 megaraid_reset(Scsi_Cmnd *cmd)
 {
@@ -2903,12 +2903,10 @@
                /*
                 * Perform the ack sequence, since interrupts are unavailable
                 */
-               if( adapter->flag & BOARD_MEMMAP ) {
+               if (adapter->flag & BOARD_MEMMAP)
                        megaraid_memmbox_ack_sequence(adapter);
-               }
-               else {
+               else
                        megaraid_iombox_ack_sequence(adapter);
-               }
 
                spin_unlock(adapter->host_lock);
 
@@ -2941,7 +2939,6 @@
        return rval;
 }
 
-
 #ifdef CONFIG_PROC_FS
 /* Following code handles /proc fs  */
 
@@ -3200,6 +3197,7 @@
        return len;
 }
 
+
 /**
  * mega_allocate_inquiry()
  * @dma_handle - handle returned for dma address
@@ -3582,7 +3580,7 @@
                 * Check for overflow. We print less than 240
                 * characters for inquiry
                 */
-               if( (len + 240) >= PAGE_SIZE ) break;
+               if( (len + 240) >= ((int) PAGE_SIZE) ) break;
 
                len += sprintf(page+len, "%s.\n", str);
 
@@ -3886,7 +3884,7 @@
                 * Check for overflow. We print less than 240 characters for
                 * information about each logical drive.
                 */
-               if( (len + 240) >= PAGE_SIZE ) break;
+               if( (len + 240) >= ((int) PAGE_SIZE) ) break;
 
                len += sprintf(page+len, "Logical drive:%2d:, ", i);
 
@@ -4172,7 +4170,7 @@
 }
 
 
-#if defined(__x86_64__)
+#ifdef LSI_CONFIG_COMPAT
 static int
 megadev_compat_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg,
                struct file *filep)
@@ -4221,7 +4219,7 @@
        megacmd_t       mc;
        megastat_t      *ustats;
        int             num_ldrv;
-       u32             uxferaddr = 0;
+       caddr_t         uxferaddr=NULL;
        struct pci_dev  *pdev;
 
        ustats = NULL; /* avoid compilation warnings */
@@ -4251,13 +4249,13 @@
        switch( uioc.opcode ) {
 
        case GET_DRIVER_VER:
-               if( put_user(driver_ver, (u32 *)uioc.uioc_uaddr) )
+               if( put_user(driver_ver, (u32 *)uioc.u_dataaddr) )
                        return (-EFAULT);
 
                break;
 
        case GET_N_ADAP:
-               if( put_user(hba_count, (u32 *)uioc.uioc_uaddr) )
+               if( put_user(hba_count, (u32 *)uioc.u_dataaddr) )
                        return (-EFAULT);
 
                /*
@@ -4275,7 +4273,7 @@
                if( (adapno = GETADAP(uioc.adapno)) >= hba_count )
                        return (-ENODEV);
 
-               if( copy_to_user(uioc.uioc_uaddr, mcontroller+adapno,
+               if( copy_to_user(uioc.u_dataaddr, mcontroller+adapno,
                                sizeof(struct mcontroller)) )
                        return (-EFAULT);
                break;
@@ -4291,7 +4289,7 @@
 
                adapter = hba_soft_state[adapno];
 
-               ustats = (megastat_t *)uioc.uioc_uaddr;
+               ustats = (megastat_t *)uioc.u_dataaddr;
 
                if( copy_from_user(&num_ldrv, &ustats->num_ldrv, sizeof(int)) )
                        return (-EFAULT);
@@ -4333,7 +4331,7 @@
                /*
                 * Which adapter
                 */
-               if( (adapno = GETADAP(uioc.adapno)) >= hba_count ) 
+               if( (adapno = GETADAP(uioc.adapno)) >= hba_count )
                        return (-ENODEV);
 
                adapter = hba_soft_state[adapno];
@@ -4342,37 +4340,37 @@
                 * Deletion of logical drive is a special case. The adapter
                 * should be quiescent before this command is issued.
                 */
-               if( uioc.uioc_rmbox[0] == FC_DEL_LOGDRV &&
-                               uioc.uioc_rmbox[2] == OP_DEL_LOGDRV ) {
+               if( RMBOX(uioc)[0] == FC_DEL_LOGDRV ) {
+                       if ( RMBOX(uioc)[2] == OP_DEL_LOGDRV ) {
+                               /*
+                                * Do we support this feature
+                                */
+                               if( !adapter->support_random_del ) {
+                                       printk(KERN_WARNING "megaraid: logdrv 
");
+                                       printk("delete on non-supporting 
F/W.\n");
 
-                       /*
-                        * Do we support this feature
-                        */
-                       if( !adapter->support_random_del ) {
-                               printk(KERN_WARNING "megaraid: logdrv ");
-                               printk("delete on non-supporting F/W.\n");
+                                       return (-EINVAL);
+                               }
 
-                               return (-EINVAL);
-                       }
+                               rval = mega_del_logdrv( adapter, RMBOX(uioc)[3] 
);
 
-                       rval = mega_del_logdrv( adapter, uioc.uioc_rmbox[3] );
+                               if( rval == 0 ) {
+                                       memset(&mc, 0, sizeof(megacmd_t));
 
-                       if( rval == 0 ) {
-                               memset(&mc, 0, sizeof(megacmd_t));
+                                       mc.status = rval;
 
-                               mc.status = rval;
+                                       rval = mega_n_to_m((void *)arg, &mc);
+                               }
 
-                               rval = mega_n_to_m((void *)arg, &mc);
+                               return rval;
                        }
-
-                       return rval;
                }
                /*
                 * This interface only support the regular passthru commands.
                 * Reject extended passthru and 64-bit passthru
                 */
-               if( uioc.uioc_rmbox[0] == MEGA_MBOXCMD_PASSTHRU64 ||
-                       uioc.uioc_rmbox[0] == MEGA_MBOXCMD_EXTPTHRU ) {
+               if( RMBOX(uioc)[0] == MEGA_MBOXCMD_PASSTHRU64 ||
+                       RMBOX(uioc)[0] == MEGA_MBOXCMD_EXTPTHRU ) {
 
                        printk(KERN_WARNING "megaraid: rejected passthru.\n");
 
@@ -4386,7 +4384,7 @@
                pdev = adapter->dev;
 
                /* Is it a passthru command or a DCMD */
-               if( uioc.uioc_rmbox[0] == MEGA_MBOXCMD_PASSTHRU ) {
+               if( RMBOX(uioc)[0] == MEGA_MBOXCMD_PASSTHRU ) {
                        /* Passthru commands */
 
                        pthru = adapter->int_pthru;
@@ -4394,20 +4392,12 @@
                        /*
                         * The user passthru structure
                         */
-                       upthru = (mega_passthru *)
-                                       ((ulong)(MBOX(uioc)->xferaddr));
-                       /*
-                        * Copy in the user passthru here.
-                        */
-                       if( copy_from_user(pthru, (char *)upthru,
-                                               sizeof(mega_passthru)) ) {
-                               return (-EFAULT);
-                       }
-
+                        upthru = &uioc.pthru;
+                        memcpy(pthru, (char *)upthru,sizeof(mega_passthru));
                        /*
                         * Is there a data transfer; If the data transfer
-                        * length is <= INT_MEMBLK_SZ, usr the buffer 
-                        * allocated at the load time. Otherwise, allocate it 
+                        * length is <= INT_MEMBLK_SZ, usr the buffer
+                        * allocated at the load time. Otherwise, allocate it
                         * here.
                         */
                        if (pthru->dataxferlen) {
@@ -4417,8 +4407,9 @@
                                                        pthru->dataxferlen,
                                                        &data_dma_hndl );
 
-                                       if (data == NULL)
+                                       if (data == NULL) {
                                                return (-ENOMEM);
+                                       }
                                }
                                else {
                                        data = adapter->int_data;
@@ -4428,11 +4419,11 @@
                                 * Save the user address and point the kernel
                                 * address at just allocated memory
                                 */
-                               uxferaddr = pthru->dataxferaddr;
+                               uxferaddr = (caddr_t) uioc.u_dataaddr;
                                if (data_dma_hndl)
                                        pthru->dataxferaddr = data_dma_hndl;
                                else
-                                       pthru->dataxferaddr = 
+                                       pthru->dataxferaddr =
                                                adapter->int_data_dma_hndl;
                        }
 
@@ -4440,12 +4431,12 @@
                        /*
                         * Is data coming down-stream
                         */
-                       if( pthru->dataxferlen && (uioc.flags & UIOC_WR) ) {
+                       if(pthru->dataxferlen  && (uioc.flags & UIOC_WR) ) {
                                /*
                                 * Get the user data
                                 */
                                if( copy_from_user(data,
-                                               (char *)((ulong)uxferaddr),
+                                               (char *)uxferaddr,
                                                pthru->dataxferlen) ) {
                                        rval = (-EFAULT);
                                        goto freedata_and_return;
@@ -4471,7 +4462,7 @@
                         * Is data going up-stream
                         */
                        if( pthru->dataxferlen && (uioc.flags & UIOC_RD) ) {
-                               if( copy_to_user((char *)((ulong)uxferaddr),
+                               if( copy_to_user((char *)uxferaddr,
                                                data, pthru->dataxferlen) ) {
                                        rval = (-EFAULT);
                                }
@@ -4511,7 +4502,7 @@
                                else {
                                        data = adapter->int_data;
                                }
-                               uxferaddr = MBOX(uioc)->xferaddr;
+                               uxferaddr = uioc.u_dataaddr;
                        }
 
                        /*
@@ -4559,7 +4550,7 @@
                         * Is data going up-stream
                         */
                        if( uioc.xferlen && (uioc.flags & UIOC_RD) ) {
-                               if( copy_to_user((char *)((ulong)uxferaddr),
+                               if( copy_to_user((char *)uxferaddr,
                                                data, uioc.xferlen) ) {
 
                                        rval = (-EFAULT);
@@ -4648,18 +4639,18 @@
 
                case MEGAIOC_QDRVRVER:  /* Query driver version */
                        uioc->opcode = GET_DRIVER_VER;
-                       uioc->uioc_uaddr = uioc_mimd.data;
+                       uioc->u_dataaddr = uioc_mimd.data;
                        break;
 
                case MEGAIOC_QNADAP:    /* Get # of adapters */
                        uioc->opcode = GET_N_ADAP;
-                       uioc->uioc_uaddr = uioc_mimd.data;
+                       uioc->u_dataaddr = uioc_mimd.data;
                        break;
 
                case MEGAIOC_QADAPINFO: /* Get adapter information */
                        uioc->opcode = GET_ADAP_INFO;
                        uioc->adapno = uioc_mimd.ui.fcs.adapno;
-                       uioc->uioc_uaddr = uioc_mimd.data;
+                       uioc->u_dataaddr = uioc_mimd.data;
                        break;
 
                default:
@@ -4674,9 +4665,16 @@
                uioc->opcode = MBOX_CMD;
                uioc->adapno = uioc_mimd.ui.fcs.adapno;
 
-               memcpy(uioc->uioc_rmbox, uioc_mimd.mbox, 18);
+               memcpy(&uioc->u_mbox, uioc_mimd.mbox, 18);
 
                uioc->xferlen = uioc_mimd.ui.fcs.length;
+               uioc->u_dataaddr = uioc_mimd.ui.fcs.buffer;
+
+               if (uioc_mimd.mbox[0] == MEGA_MBOXCMD_PASSTHRU ) {
+                       memcpy(&uioc->pthru,&uioc_mimd.pthru,
+                               sizeof(mega_passthru));
+
+               }
 
                if( uioc_mimd.outlen ) uioc->flags = UIOC_RD;
                if( uioc_mimd.inlen ) uioc->flags |= UIOC_WR;
@@ -4688,13 +4686,20 @@
                uioc->opcode = MBOX_CMD;
                uioc->adapno = uioc_mimd.ui.fcs.adapno;
 
-               memcpy(uioc->uioc_rmbox, uioc_mimd.mbox, 18);
+               memcpy(&uioc->u_mbox, uioc_mimd.mbox, 18);
 
                /*
                 * Choose the xferlen bigger of input and output data
                 */
                uioc->xferlen = uioc_mimd.outlen > uioc_mimd.inlen ?
                        uioc_mimd.outlen : uioc_mimd.inlen;
+               uioc->u_dataaddr = uioc_mimd.data;
+
+               if (uioc_mimd.mbox[0] == MEGA_MBOXCMD_PASSTHRU ) {
+                       memcpy(&uioc->pthru,&uioc_mimd.pthru,
+                               sizeof(mega_passthru));
+
+               }
 
                if( uioc_mimd.outlen ) uioc->flags = UIOC_RD;
                if( uioc_mimd.inlen ) uioc->flags |= UIOC_WR;
@@ -4720,7 +4725,6 @@
 static int
 mega_n_to_m(void *arg, megacmd_t *mc)
 {
-       nitioctl_t      *uiocp;
        megacmd_t       *umc;
        megacmd_t       kmc;
        mega_passthru   *upthru;
@@ -4735,20 +4739,14 @@
 
        if( memcmp(signature, "MEGANIT", 7) == 0 ) {
 
-               uiocp = (nitioctl_t *)arg;
-
-               if( put_user(mc->status, (u8 *)&MBOX_P(uiocp)->status) )
-                       return (-EFAULT);
-
-               if( mc->cmd == MEGA_MBOXCMD_PASSTHRU ) {
-
-                       umc = MBOX_P(uiocp);
 
-                       upthru = (mega_passthru *)((ulong)(umc->xferaddr));
-
-                       if( put_user(mc->status, (u8 *)&upthru->scsistatus) )
-                               return (-EFAULT);
-               }
+               /*
+                * NOTE: The nit ioctl is still under flux because of
+                * change of mailbox definition, in HPE. No applications yet
+                * use this interface and let's not have applications use this
+                * interface till the new specifitions are in place.
+                */
+               return -EINVAL;
        }
        else {
                uioc_mimd = (struct uioctl_t *)arg;
@@ -4763,8 +4761,7 @@
                        if (copy_from_user(&kmc, umc, sizeof(megacmd_t))) {
                                return -EFAULT;
                        }
-
-                       upthru = (mega_passthru *)((ulong)kmc.xferaddr);
+                       upthru = (mega_passthru *)((ulong)&uioc_mimd->pthru);
 
                        if( put_user(mc->status, (u8 *)&upthru->scsistatus) ){
                                return (-EFAULT);
@@ -5179,6 +5176,7 @@
 }
 
 
+
 /**
  * mega_reorder_hosts()
  *
@@ -5393,7 +5391,6 @@
 }
 
 
-
 /** mega_internal_dev_inquiry()
  * @adapter - pointer to our soft state
  * @ch - channel for this device
diff -urN linux/drivers/scsi/megaraid2.h linux/drivers/scsi/megaraid2.h
--- linux/drivers/scsi/Attic/megaraid2.h        2005/03/18 12:13:27     1.1.2.5
+++ linux/drivers/scsi/Attic/megaraid2.h        2005/09/23 20:41:23     1.1.2.6
@@ -6,7 +6,7 @@
 
 
 #define MEGARAID_VERSION       \
-       "v2.10.8.2 (Release Date: Mon Jul 26 12:15:51 EDT 2004)\n"
+       "v2.10.10.1 (Release Date: Thu Jan 27 16:19:44 EDT 2005)\n"
 
 /*
  * Driver features - change the values to enable or disable features in the
@@ -83,6 +83,7 @@
 #define INTEL_SUBSYS_VID               0x8086
 #define FSC_SUBSYS_VID                 0x1734
 #define ACER_SUBSYS_VID                        0x1025
+#define NEC_SUBSYS_VID                 0x1033
 
 #define HBA_SIGNATURE                  0x3344
 #define HBA_SIGNATURE_471              0xCCCC
@@ -707,15 +708,15 @@
        char            signature[8];   /* Must contain "MEGANIT" */
        u32             opcode;         /* opcode for the command */
        u32             adapno;         /* adapter number */
-       union {
-               u8      __raw_mbox[18];
-               caddr_t __uaddr; /* xferaddr for non-mbox cmds */
-       }__ua;
-
-#define uioc_rmbox     __ua.__raw_mbox
-#define MBOX(uioc)     ((megacmd_t *)&((uioc).__ua.__raw_mbox[0]))
-#define MBOX_P(uioc)   ((megacmd_t *)&((uioc)->__ua.__raw_mbox[0]))
-#define uioc_uaddr     __ua.__uaddr
+       mbox_t          u_mbox;         /* user mailbox */
+       caddr_t         u_dataaddr;     /* xferaddr for DCMD and non-mbox
+                                          commands */
+       mega_passthru   pthru;
+
+#define RMBOX(uioc)    ((u8 *)&(uioc).u_mbox)
+#define MBOX(uioc)     ((megacmd_t *)&(uioc).u_mbox)
+#define MBOX_P(uioc)   ((megacmd_t *)&(uioc)->u_mbox)
+
 
        u32             xferlen;        /* xferlen for DCMD and non-mbox
                                           commands */
@@ -1128,7 +1129,7 @@
                              u32 *buffer, u32 *length);
 static inline int mega_busywait_mbox (adapter_t *);
 static int __mega_busywait_mbox (adapter_t *);
-static void mega_cmd_done(adapter_t *, u8 [], int, int);
+static inline void mega_cmd_done(adapter_t *, u8 [], int, int);
 static inline void mega_free_sgl (adapter_t *adapter);
 static void mega_8_to_40ld (mraid_inquiry *inquiry,
                mega_inquiry3 *enquiry3, mega_product_info *);
@@ -1137,7 +1138,14 @@
                                   unsigned long, void *);
 static int megadev_open (struct inode *, struct file *);
 
-#if defined(__x86_64__)
+#if defined( __x86_64__) || defined(IA32_EMULATION)
+#ifndef __ia64__
+#define LSI_CONFIG_COMPAT
+#endif
+#endif
+
+
+#ifdef LSI_CONFIG_COMPAT
 static int megadev_compat_ioctl(unsigned int, unsigned int, unsigned long,
        struct file *);
 #endif
diff -urN linux/drivers/scsi/sata_nv.c linux/drivers/scsi/sata_nv.c
--- linux/drivers/scsi/sata_nv.c        2005/03/18 12:13:28     1.8.2.4
+++ linux/drivers/scsi/sata_nv.c        2005/09/23 20:41:23     1.8.2.5
@@ -329,6 +329,8 @@
                host->host_desc->disable_hotplug(host_set);
 
        kfree(host);
+
+       ata_host_stop(host_set);
 }
 
 static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
diff -urN linux/drivers/scsi/sata_promise.c linux/drivers/scsi/sata_promise.c
--- linux/drivers/scsi/sata_promise.c   2005/03/18 12:13:28     1.12.2.4
+++ linux/drivers/scsi/sata_promise.c   2005/09/23 20:41:23     1.12.2.5
@@ -42,6 +42,7 @@
 #define DRV_NAME       "sata_promise"
 #define DRV_VERSION    "1.01"
 
+
 enum {
        PDC_PKT_SUBMIT          = 0x40, /* Command packet pointer addr */
        PDC_INT_SEQMASK         = 0x40, /* Mask of asserted SEQ INTs */
@@ -58,6 +59,7 @@
 
        board_2037x             = 0,    /* FastTrak S150 TX2plus */
        board_20319             = 1,    /* FastTrak S150 TX4 */
+       board_20619             = 2,    /* FastTrak TX4000 */
 
        PDC_HAS_PATA            = (1 << 1), /* PDC20375 has PATA */
 
@@ -121,6 +123,7 @@
        .scr_write              = pdc_sata_scr_write,
        .port_start             = pdc_port_start,
        .port_stop              = pdc_port_stop,
+       .host_stop              = ata_host_stop,
 };
 
 static struct ata_port_info pdc_port_info[] = {
@@ -145,11 +148,24 @@
                .udma_mask      = 0x7f, /* udma0-6 ; FIXME */
                .port_ops       = &pdc_ata_ops,
        },
+
+       /* board_20619 */
+       {
+               .sht            = &pdc_ata_sht,
+               .host_flags     = ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST |
+                                 ATA_FLAG_MMIO | ATA_FLAG_SLAVE_POSS,
+               .pio_mask       = 0x1f, /* pio0-4 */
+               .mwdma_mask     = 0x07, /* mwdma0-2 */
+               .udma_mask      = 0x7f, /* udma0-6 ; FIXME */
+               .port_ops       = &pdc_ata_ops,
+       },
 };
 
 static struct pci_device_id pdc_ata_pci_tbl[] = {
        { PCI_VENDOR_ID_PROMISE, 0x3371, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
          board_2037x },
+       { PCI_VENDOR_ID_PROMISE, 0x3571, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+         board_2037x },
        { PCI_VENDOR_ID_PROMISE, 0x3373, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
          board_2037x },
        { PCI_VENDOR_ID_PROMISE, 0x3375, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
@@ -168,6 +184,9 @@
        { PCI_VENDOR_ID_PROMISE, 0x3d18, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
          board_20319 },
 
+       { PCI_VENDOR_ID_PROMISE, 0x6629, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+         board_20619 },
+
        { }     /* terminate list */
 };
 
@@ -629,6 +648,15 @@
        case board_2037x:
                        probe_ent->n_ports = 2;
                break;
+       case board_20619:
+               probe_ent->n_ports = 4;
+
+               pdc_ata_setup_port(&probe_ent->port[2], base + 0x300);
+               pdc_ata_setup_port(&probe_ent->port[3], base + 0x380);
+
+               probe_ent->port[2].scr_addr = base + 0x600;
+               probe_ent->port[3].scr_addr = base + 0x700;
+               break;
        default:
                BUG();
                break;
@@ -684,7 +712,7 @@
 
 
 MODULE_AUTHOR("Jeff Garzik");
-MODULE_DESCRIPTION("Promise SATA TX2/TX4 low-level driver");
+MODULE_DESCRIPTION("Promise ATA TX2/TX4/TX4000 low-level driver");
 MODULE_LICENSE("GPL");
 MODULE_DEVICE_TABLE(pci, pdc_ata_pci_tbl);
 MODULE_VERSION(DRV_VERSION);
diff -urN linux/drivers/scsi/sata_qstor.c linux/drivers/scsi/sata_qstor.c
--- linux/drivers/scsi/sata_qstor.c     2005/03/18 12:13:28     1.1.2.1
+++ linux/drivers/scsi/sata_qstor.c     2005/09/23 20:41:24     1.1.2.2
@@ -537,6 +537,8 @@
 
        writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */
        writeb(QS_CNFG3_GSRST, mmio_base + QS_HCF_CNFG3); /* global reset */
+
+       ata_host_stop(host_set);
 }
 
 static void qs_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
diff -urN linux/drivers/scsi/sata_sil.c linux/drivers/scsi/sata_sil.c
--- linux/drivers/scsi/sata_sil.c       2005/05/23 12:12:31     1.10.2.5
+++ linux/drivers/scsi/sata_sil.c       2005/09/23 20:41:24     1.10.2.6
@@ -82,6 +82,7 @@
        { 0x1095, 0x3114, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3114 },
        { 0x1002, 0x436e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
        { 0x1002, 0x4379, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
+       { 0x1002, 0x437a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
        { }     /* terminate list */
 };
 
@@ -160,6 +161,7 @@
        .scr_write              = sil_scr_write,
        .port_start             = ata_port_start,
        .port_stop              = ata_port_stop,
+       .host_stop              = ata_host_stop,
 };
 
 static struct ata_port_info sil_port_info[] = {
@@ -427,7 +429,13 @@
                writeb(cls, mmio_base + SIL_FIFO_R0);
                writeb(cls, mmio_base + SIL_FIFO_W0);
                writeb(cls, mmio_base + SIL_FIFO_R1);
-               writeb(cls, mmio_base + SIL_FIFO_W2);
+               writeb(cls, mmio_base + SIL_FIFO_W1);
+               if (ent->driver_data == sil_3114) {
+                       writeb(cls, mmio_base + SIL_FIFO_R2);
+                       writeb(cls, mmio_base + SIL_FIFO_W2);
+                       writeb(cls, mmio_base + SIL_FIFO_R3);
+                       writeb(cls, mmio_base + SIL_FIFO_W3);
+               }
        } else
                printk(KERN_WARNING DRV_NAME "(%s): cache line size not set.  
Driver may not function\n",
                        pci_name(pdev));
diff -urN linux/drivers/scsi/sata_sis.c linux/drivers/scsi/sata_sis.c
--- linux/drivers/scsi/sata_sis.c       2005/03/18 12:13:28     1.6.2.4
+++ linux/drivers/scsi/sata_sis.c       2005/09/23 20:41:24     1.6.2.5
@@ -114,6 +114,7 @@
        .scr_write              = sis_scr_write,
        .port_start             = ata_port_start,
        .port_stop              = ata_port_stop,
+       .host_stop              = ata_host_stop,
 };
 
 static struct ata_port_info sis_port_info = {
diff -urN linux/drivers/scsi/sata_svw.c linux/drivers/scsi/sata_svw.c
--- linux/drivers/scsi/sata_svw.c       2005/05/23 12:12:31     1.11.2.5
+++ linux/drivers/scsi/sata_svw.c       2005/09/23 20:41:24     1.11.2.6
@@ -49,7 +49,7 @@
 #endif /* CONFIG_PPC_OF */
 
 #define DRV_NAME       "sata_svw"
-#define DRV_VERSION    "1.05"
+#define DRV_VERSION    "1.06"
 
 /* Taskfile registers offsets */
 #define K2_SATA_TF_CMD_OFFSET          0x00
@@ -313,6 +313,7 @@
        .scr_write              = k2_sata_scr_write,
        .port_start             = ata_port_start,
        .port_stop              = ata_port_stop,
+       .host_stop              = ata_host_stop,
 };
 
 static void k2_sata_setup_port(struct ata_ioports *port, unsigned long base)
@@ -343,6 +344,7 @@
        void *mmio_base;
        int pci_dev_busy = 0;
        int rc;
+       int i;
 
        if (!printed_version++)
                printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
@@ -417,11 +419,11 @@
        probe_ent->mwdma_mask = 0x7;
        probe_ent->udma_mask = 0x7f;
 
-       /* We have 4 ports per PCI function */
-       k2_sata_setup_port(&probe_ent->port[0], base + 0 * K2_SATA_PORT_OFFSET);
-       k2_sata_setup_port(&probe_ent->port[1], base + 1 * K2_SATA_PORT_OFFSET);
-       k2_sata_setup_port(&probe_ent->port[2], base + 2 * K2_SATA_PORT_OFFSET);
-       k2_sata_setup_port(&probe_ent->port[3], base + 3 * K2_SATA_PORT_OFFSET);
+       /* different controllers have different number of ports - currently 4 
or 8 */
+       /* All ports are on the same function. Multi-function device is no
+        * longer available. This should not be seen in any system. */
+       for (i = 0; i < ent->driver_data; i++)
+               k2_sata_setup_port(&probe_ent->port[i], base + i * 
K2_SATA_PORT_OFFSET);
 
        pci_set_master(pdev);
 
@@ -439,11 +441,17 @@
        return rc;
 }
 
-
+/* 0x240 is device ID for Apple K2 device
+ * 0x241 is device ID for Serverworks Frodo4
+ * 0x242 is device ID for Serverworks Frodo8
+ * 0x24a is device ID for BCM5785 (aka HT1000) HT southbridge integrated SATA
+ * controller
+ * */
 static struct pci_device_id k2_sata_pci_tbl[] = {
-       { 0x1166, 0x0240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
-       { 0x1166, 0x0241, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
-       { 0x1166, 0x0242, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+       { 0x1166, 0x0240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
+       { 0x1166, 0x0241, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
+       { 0x1166, 0x0242, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
+       { 0x1166, 0x024a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
        { }
 };
 
diff -urN linux/drivers/scsi/sata_sx4.c linux/drivers/scsi/sata_sx4.c
--- linux/drivers/scsi/sata_sx4.c       2005/03/18 12:13:28     1.4.2.4
+++ linux/drivers/scsi/sata_sx4.c       2005/09/23 20:41:24     1.4.2.5
@@ -245,6 +245,8 @@
 
        iounmap(dimm_mmio);
        kfree(hpriv);
+
+       ata_host_stop(host_set);
 }
 
 static int pdc_port_start(struct ata_port *ap)
diff -urN linux/drivers/scsi/sata_uli.c linux/drivers/scsi/sata_uli.c
--- linux/drivers/scsi/sata_uli.c       2005/03/18 12:13:28     1.2.2.4
+++ linux/drivers/scsi/sata_uli.c       2005/09/23 20:41:24     1.2.2.5
@@ -113,6 +113,7 @@
 
        .port_start             = ata_port_start,
        .port_stop              = ata_port_stop,
+       .host_stop              = ata_host_stop,
 };
 
 static struct ata_port_info uli_port_info = {
diff -urN linux/drivers/scsi/sata_via.c linux/drivers/scsi/sata_via.c
--- linux/drivers/scsi/sata_via.c       2005/03/18 12:13:28     1.10.2.4
+++ linux/drivers/scsi/sata_via.c       2005/09/23 20:41:24     1.10.2.5
@@ -134,6 +134,7 @@
 
        .port_start             = ata_port_start,
        .port_stop              = ata_port_stop,
+       .host_stop              = ata_host_stop,
 };
 
 static struct ata_port_info svia_port_info = {
diff -urN linux/drivers/scsi/sata_vsc.c linux/drivers/scsi/sata_vsc.c
--- linux/drivers/scsi/sata_vsc.c       2005/03/18 12:13:28     1.6.2.4
+++ linux/drivers/scsi/sata_vsc.c       2005/09/23 20:41:24     1.6.2.5
@@ -230,6 +230,7 @@
        .scr_write              = vsc_sata_scr_write,
        .port_start             = ata_port_start,
        .port_stop              = ata_port_stop,
+       .host_stop              = ata_host_stop,
 };
 
 static void __devinit vsc_sata_setup_port(struct ata_ioports *port, unsigned 
long base)
diff -urN linux/drivers/sound/i810_audio.c linux/drivers/sound/i810_audio.c
--- linux/drivers/sound/Attic/i810_audio.c      2004/11/19 00:28:46     
1.24.2.12
+++ linux/drivers/sound/Attic/i810_audio.c      2005/09/23 20:41:24     
1.24.2.13
@@ -458,12 +458,38 @@
 /* extract register offset from codec struct */
 #define IO_REG_OFF(codec) (((struct i810_card *) 
codec->private_data)->ac97_id_map[codec->id])
 
-#define GET_CIV(port) MODULOP2(inb((port) + OFF_CIV), SG_LEN)
-#define GET_LVI(port) MODULOP2(inb((port) + OFF_LVI), SG_LEN)
+#define I810_IOREAD(size, type, card, off)                             \
+({                                                                     \
+       type val;                                                       \
+       if (card->use_mmio)                                             \
+               val=read##size(card->iobase_mmio+off);                  \
+       else                                                            \
+               val=in##size(card->iobase+off);                         \
+       val;                                                            \
+})
+
+#define I810_IOREADL(card, off)                I810_IOREAD(l, u32, card, off)
+#define I810_IOREADW(card, off)                I810_IOREAD(w, u16, card, off)
+#define I810_IOREADB(card, off)                I810_IOREAD(b, u8,  card, off)
+
+#define I810_IOWRITE(size, val, card, off)                             \
+({                                                                     \
+       if (card->use_mmio)                                             \
+               write##size(val, card->iobase_mmio+off);                \
+       else                                                            \
+               out##size(val, card->iobase+off);                       \
+})
+
+#define I810_IOWRITEL(val, card, off)  I810_IOWRITE(l, val, card, off)
+#define I810_IOWRITEW(val, card, off)  I810_IOWRITE(w, val, card, off)
+#define I810_IOWRITEB(val, card, off)  I810_IOWRITE(b, val, card, off)
+
+#define GET_CIV(card, port) MODULOP2(I810_IOREADB((card), (port) + OFF_CIV), 
SG_LEN)
+#define GET_LVI(card, port) MODULOP2(I810_IOREADB((card), (port) + OFF_LVI), 
SG_LEN)
 
 /* set LVI from CIV */
-#define CIV_TO_LVI(port, off) \
-       outb(MODULOP2(GET_CIV((port)) + (off), SG_LEN), (port) + OFF_LVI)
+#define CIV_TO_LVI(card, port, off) \
+       I810_IOWRITEB(MODULOP2(GET_CIV((card), (port)) + (off), SG_LEN), 
(card), (port) + OFF_LVI)
 
 static struct i810_card *devs = NULL;
 
@@ -722,9 +748,9 @@
                return 0;
 
        if (rec)
-               port = state->card->iobase + dmabuf->read_channel->port;
+               port = dmabuf->read_channel->port;
        else
-               port = state->card->iobase + dmabuf->write_channel->port;
+               port = dmabuf->write_channel->port;
 
        if(state->card->pci_id == PCI_DEVICE_ID_SI_7012) {
                port_picb = port + OFF_SR;
@@ -733,8 +759,8 @@
                port_picb = port + OFF_PICB;
 
        do {
-               civ = GET_CIV(port);
-               offset = inw(port_picb);
+               civ = GET_CIV(state->card, port);
+               offset = I810_IOREADW(state->card, port_picb);
                /* Must have a delay here! */ 
                if(offset == 0)
                        udelay(1);
@@ -753,7 +779,7 @@
                 * that we won't have to worry about the chip still being
                 * out of sync with reality ;-)
                 */
-       } while (civ != GET_CIV(port) || offset != inw(port_picb));
+       } while (civ != GET_CIV(state->card, port) || offset != 
I810_IOREADW(state->card, port_picb));
                 
        return (((civ + 1) * dmabuf->fragsize - (bytes * offset))
                % dmabuf->dmasize);
@@ -766,15 +792,15 @@
        struct i810_card *card = state->card;
 
        dmabuf->enable &= ~ADC_RUNNING;
-       outb(0, card->iobase + PI_CR);
+       I810_IOWRITEB(0, card, PI_CR);
        // wait for the card to acknowledge shutdown
-       while( inb(card->iobase + PI_CR) != 0 ) ;
+       while( I810_IOREADB(card, PI_CR) != 0 ) ;
        // now clear any latent interrupt bits (like the halt bit)
        if(card->pci_id == PCI_DEVICE_ID_SI_7012)
-               outb( inb(card->iobase + PI_PICB), card->iobase + PI_PICB );
+               I810_IOWRITEB( I810_IOREADB(card, PI_PICB), card, PI_PICB );
        else
-               outb( inb(card->iobase + PI_SR), card->iobase + PI_SR );
-       outl( inl(card->iobase + GLOB_STA) & INT_PI, card->iobase + GLOB_STA);
+               I810_IOWRITEB( I810_IOREADB(card, PI_SR), card, PI_SR );
+       I810_IOWRITEL( I810_IOREADL(card, GLOB_STA) & INT_PI, card, GLOB_STA);
 }
 
 static void stop_adc(struct i810_state *state)
@@ -795,7 +821,7 @@
            (dmabuf->trigger & PCM_ENABLE_INPUT)) {
                dmabuf->enable |= ADC_RUNNING;
                // Interrupt enable, LVI enable, DMA enable
-               outb(0x10 | 0x04 | 0x01, state->card->iobase + PI_CR);
+               I810_IOWRITEB(0x10 | 0x04 | 0x01, state->card, PI_CR);
        }
 }
 
@@ -816,15 +842,15 @@
        struct i810_card *card = state->card;
 
        dmabuf->enable &= ~DAC_RUNNING;
-       outb(0, card->iobase + PO_CR);
+       I810_IOWRITEB(0, card, PO_CR);
        // wait for the card to acknowledge shutdown
-       while( inb(card->iobase + PO_CR) != 0 ) ;
+       while( I810_IOREADB(card, PO_CR) != 0 ) ;
        // now clear any latent interrupt bits (like the halt bit)
        if(card->pci_id == PCI_DEVICE_ID_SI_7012)
-               outb( inb(card->iobase + PO_PICB), card->iobase + PO_PICB );
+               I810_IOWRITEB( I810_IOREADB(card, PO_PICB), card, PO_PICB );
        else
-               outb( inb(card->iobase + PO_SR), card->iobase + PO_SR );
-       outl( inl(card->iobase + GLOB_STA) & INT_PO, card->iobase + GLOB_STA);
+               I810_IOWRITEB( I810_IOREADB(card, PO_SR), card, PO_SR );
+       I810_IOWRITEL( I810_IOREADL(card, GLOB_STA) & INT_PO, card, GLOB_STA);
 }
 
 static void stop_dac(struct i810_state *state)
@@ -845,7 +871,7 @@
            (dmabuf->trigger & PCM_ENABLE_OUTPUT)) {
                dmabuf->enable |= DAC_RUNNING;
                // Interrupt enable, LVI enable, DMA enable
-               outb(0x10 | 0x04 | 0x01, state->card->iobase + PO_CR);
+               I810_IOWRITEB(0x10 | 0x04 | 0x01, state->card, PO_CR);
        }
 }
 static void start_dac(struct i810_state *state)
@@ -1008,12 +1034,12 @@
                        sg++;
                }
                spin_lock_irqsave(&state->card->lock, flags);
-               outb(2, state->card->iobase+c->port+OFF_CR);   /* reset DMA 
machine */
-               while( inb(state->card->iobase+c->port+OFF_CR) & 0x02 ) ;
-               outl((u32)state->card->chandma +
+               I810_IOWRITEB(2, state->card, c->port+OFF_CR);   /* reset DMA 
machine */
+               while( I810_IOREADB(state->card, c->port+OFF_CR) & 0x02 ) ;
+               I810_IOWRITEL((u32)state->card->chandma +
                    c->num*sizeof(struct i810_channel),
-                   state->card->iobase+c->port+OFF_BDBAR);
-               CIV_TO_LVI(state->card->iobase+c->port, 0);
+                   state->card, c->port+OFF_BDBAR);
+               CIV_TO_LVI(state->card, c->port, 0);
 
                spin_unlock_irqrestore(&state->card->lock, flags);
 
@@ -1045,14 +1071,13 @@
        void (*start)(struct i810_state *);
 
        count = dmabuf->count;
-       port = state->card->iobase;
        if (rec) {
-               port += dmabuf->read_channel->port;
+               port = dmabuf->read_channel->port;
                trigger = PCM_ENABLE_INPUT;
                start = __start_adc;
                count = dmabuf->dmasize - count;
        } else {
-               port += dmabuf->write_channel->port;
+               port = dmabuf->write_channel->port;
                trigger = PCM_ENABLE_OUTPUT;
                start = __start_dac;
        }
@@ -1062,19 +1087,32 @@
        if (count < fragsize)
                return;
 
+       /* if we are currently stopped, then our CIV is actually set to our
+        * *last* sg segment and we are ready to wrap to the next.  However,
+        * if we set our LVI to the last sg segment, then it won't wrap to
+        * the next sg segment, it won't even get a start.  So, instead, when
+        * we are stopped, we set both the LVI value and also we increment
+        * the CIV value to the next sg segment to be played so that when
+        * we call start, things will operate properly.  Since the CIV can't
+        * be written to directly for this purpose, we set the LVI to CIV + 1
+        * temporarily.  Once the engine has started we set the LVI to its
+        * final value.
+        */
        if (!dmabuf->enable && dmabuf->ready) {
                if (!(dmabuf->trigger & trigger))
                        return;
 
+               CIV_TO_LVI(state->card, port, 1);
+
                start(state);
-               while (!(inb(port + OFF_CR) & ((1<<4) | (1<<2))))
+               while (!(I810_IOREADB(state->card, port + OFF_CR) & ((1<<4) | 
(1<<2))))
                        ;
        }
 
        /* MASKP2(swptr, fragsize) - 1 is the tail of our transfer */
        x = MODULOP2(MASKP2(dmabuf->swptr, fragsize) - 1, dmabuf->dmasize);
        x >>= dmabuf->fragshift;
-       outb(x, port + OFF_LVI);
+       I810_IOWRITEB(x, state->card, port + OFF_LVI);
 }
 
 static void i810_update_lvi(struct i810_state *state, int rec)
@@ -1116,8 +1154,8 @@
                        /* this is normal for the end of a read */
                        /* only give an error if we went past the */
                        /* last valid sg entry */
-                       if (GET_CIV(state->card->iobase + PI_BASE) !=
-                           GET_LVI(state->card->iobase + PI_BASE)) {
+                       if (GET_CIV(state->card, PI_BASE) !=
+                           GET_LVI(state->card, PI_BASE)) {
                                printk(KERN_WARNING "i810_audio: DMA overrun on 
read\n");
                                dmabuf->error++;
                        }
@@ -1141,13 +1179,13 @@
                        /* this is normal for the end of a write */
                        /* only give an error if we went past the */
                        /* last valid sg entry */
-                       if (GET_CIV(state->card->iobase + PO_BASE) !=
-                           GET_LVI(state->card->iobase + PO_BASE)) {
+                       if (GET_CIV(state->card, PO_BASE) !=
+                           GET_LVI(state->card, PO_BASE)) {
                                printk(KERN_WARNING "i810_audio: DMA overrun on 
write\n");
                                printk("i810_audio: CIV %d, LVI %d, hwptr %x, "
                                        "count %d\n",
-                                       GET_CIV(state->card->iobase + PO_BASE),
-                                       GET_LVI(state->card->iobase + PO_BASE),
+                                       GET_CIV(state->card, PO_BASE),
+                                       GET_LVI(state->card, PO_BASE),
                                        dmabuf->hwptr, dmabuf->count);
                                dmabuf->error++;
                        }
@@ -1295,7 +1333,7 @@
                struct i810_state *state = card->states[i];
                struct i810_channel *c;
                struct dmabuf *dmabuf;
-               unsigned long port = card->iobase;
+               unsigned long port;
                u16 status;
                
                if(!state)
@@ -1310,12 +1348,12 @@
                } else  /* This can occur going from R/W to close */
                        continue;
                
-               port+=c->port;
+               port = c->port;
 
                if(card->pci_id == PCI_DEVICE_ID_SI_7012)
-                       status = inw(port + OFF_PICB);
+                       status = I810_IOREADW(card, port + OFF_PICB);
                else
-                       status = inw(port + OFF_SR);
+                       status = I810_IOREADW(card, port + OFF_SR);
 
 #ifdef DEBUG_INTERRUPTS
                printk("NUM %d PORT %X IRQ ( ST%d ", c->num, c->port, status);
@@ -1348,7 +1386,7 @@
                        if(dmabuf->enable & ADC_RUNNING)
                                count = dmabuf->dmasize - count;
                        if (count >= (int)dmabuf->fragsize) {
-                               outb(inb(port+OFF_CR) | 1, port+OFF_CR);
+                               I810_IOWRITEB(I810_IOREADB(card, port+OFF_CR) | 
1, card, port+OFF_CR);
 #ifdef DEBUG_INTERRUPTS
                                printk(" CONTINUE ");
 #endif
@@ -1364,9 +1402,9 @@
                        }
                }
                if(card->pci_id == PCI_DEVICE_ID_SI_7012)
-                       outw(status & DMA_INT_MASK, port + OFF_PICB);
+                       I810_IOWRITEW(status & DMA_INT_MASK, card, port + 
OFF_PICB);
                else
-                       outw(status & DMA_INT_MASK, port + OFF_SR);
+                       I810_IOWRITEW(status & DMA_INT_MASK, card, port + 
OFF_SR);
        }
 #ifdef DEBUG_INTERRUPTS
        printk(")\n");
@@ -1380,7 +1418,7 @@
 
        spin_lock(&card->lock);
 
-       status = inl(card->iobase + GLOB_STA);
+       status = I810_IOREADL(card, GLOB_STA);
 
        if(!(status & INT_MASK)) 
        {
@@ -1392,7 +1430,7 @@
                i810_channel_interrupt(card);
 
        /* clear 'em */
-       outl(status & INT_MASK, card->iobase + GLOB_STA);
+       I810_IOWRITEL(status & INT_MASK, card, GLOB_STA);
        spin_unlock(&card->lock);
        return IRQ_HANDLED;
 }
@@ -1790,13 +1828,13 @@
                        __stop_adc(state);
                }
                if (c != NULL) {
-                       outb(2, state->card->iobase+c->port+OFF_CR);   /* reset 
DMA machine */
-                       while ( inb(state->card->iobase+c->port+OFF_CR) & 2 )
+                       I810_IOWRITEB(2, state->card, c->port+OFF_CR);   /* 
reset DMA machine */
+                       while ( I810_IOREADB(state->card, c->port+OFF_CR) & 2 )
                                cpu_relax();
-                       outl((u32)state->card->chandma +
+                       I810_IOWRITEL((u32)state->card->chandma +
                            c->num*sizeof(struct i810_channel),
-                           state->card->iobase+c->port+OFF_BDBAR);
-                       CIV_TO_LVI(state->card->iobase+c->port, 0);
+                           state->card, c->port+OFF_BDBAR);
+                       CIV_TO_LVI(state->card, c->port, 0);
                }
 
                spin_unlock_irqrestore(&state->card->lock, flags);
@@ -1926,7 +1964,7 @@
                /* Global Status and Global Control register are now  */
                /* used to indicate this.                             */
 
-                i_glob_cnt = inl(state->card->iobase + GLOB_CNT);
+                i_glob_cnt = I810_IOREADL(state->card, GLOB_CNT);
 
                /* Current # of channels enabled */
                if ( i_glob_cnt & 0x0100000 )
@@ -1938,14 +1976,14 @@
 
                switch ( val ) {
                        case 2: /* 2 channels is always supported */
-                               outl(i_glob_cnt & 0xffcfffff,
-                                    state->card->iobase + GLOB_CNT);
+                               I810_IOWRITEL(i_glob_cnt & 0xffcfffff,
+                                    state->card, GLOB_CNT);
                                /* Do we need to change mixer settings????  */
                                break;
                        case 4: /* Supported on some chipsets, better check 
first */
                                if ( state->card->channels >= 4 ) {
-                                       outl((i_glob_cnt & 0xffcfffff) | 
0x100000,
-                                             state->card->iobase + GLOB_CNT);
+                                       I810_IOWRITEL((i_glob_cnt & 0xffcfffff) 
| 0x100000,
+                                             state->card, GLOB_CNT);
                                        /* Do we need to change mixer 
settings??? */
                                } else {
                                        val = ret;
@@ -1953,8 +1991,8 @@
                                break;
                        case 6: /* Supported on some chipsets, better check 
first */
                                if ( state->card->channels >= 6 ) {
-                                       outl((i_glob_cnt & 0xffcfffff) | 
0x200000,
-                                             state->card->iobase + GLOB_CNT);
+                                       I810_IOWRITEL((i_glob_cnt & 0xffcfffff) 
| 0x200000,
+                                             state->card, GLOB_CNT);
                                        /* Do we need to change mixer 
settings??? */
                                } else {
                                        val = ret;
@@ -2483,8 +2521,8 @@
                } else {
                        i810_set_dac_rate(state, 8000);
                        /* Put the ACLink in 2 channel mode by default */
-                       i = inl(card->iobase + GLOB_CNT);
-                       outl(i & 0xffcfffff, card->iobase + GLOB_CNT);
+                       i = I810_IOREADL(card, GLOB_CNT);
+                       I810_IOWRITEL(i & 0xffcfffff, card, GLOB_CNT);
                }
        }
                
@@ -2575,7 +2613,7 @@
        int count = 100;
        u16 reg_set = IO_REG_OFF(dev) | (reg&0x7f);
        
-       while(count-- && (inb(card->iobase + CAS) & 1)) 
+       while(count-- && (I810_IOREADB(card, CAS) & 1))
                udelay(1);
        
        return inw(card->ac97base + reg_set);
@@ -2603,7 +2641,7 @@
        int count = 100;
        u16 reg_set = IO_REG_OFF(dev) | (reg&0x7f);
        
-       while(count-- && (inb(card->iobase + CAS) & 1)) 
+       while(count-- && (I810_IOREADB(card, CAS) & 1))
                udelay(1);
        
         outw(data, card->ac97base + reg_set);
@@ -2692,7 +2730,7 @@
 
 static inline int i810_ac97_exists(struct i810_card *card, int ac97_number)
 {
-       u32 reg = inl(card->iobase + GLOB_STA);
+       u32 reg = I810_IOREADL(card, GLOB_STA);
        switch (ac97_number) {
        case 0:
                return reg & (1<<8);
@@ -2763,7 +2801,7 @@
  
 static int i810_ac97_power_up_bus(struct i810_card *card)
 {      
-       u32 reg = inl(card->iobase + GLOB_CNT);
+       u32 reg = I810_IOREADL(card, GLOB_CNT);
        int i;
        int primary_codec_id = 0;
 
@@ -2775,14 +2813,14 @@
        reg&=~8;        /* ACLink on */
        
        /* At this point we deassert AC_RESET # */
-       outl(reg , card->iobase + GLOB_CNT);
+       I810_IOWRITEL(reg , card, GLOB_CNT);
 
        /* We must now allow time for the Codec initialisation.
           600mS is the specified time */
                
        for(i=0;i<10;i++)
        {
-               if((inl(card->iobase+GLOB_CNT)&4)==0)
+               if((I810_IOREADL(card, GLOB_CNT)&4)==0)
                        break;
 
                set_current_state(TASK_UNINTERRUPTIBLE);
@@ -2801,8 +2839,11 @@
         *      See if the primary codec comes ready. This must happen
         *      before we start doing DMA stuff
         */     
-       /* see i810_ac97_init for the next 7 lines (jsaw) */
-       inw(card->ac97base);
+       /* see i810_ac97_init for the next 10 lines (jsaw) */
+       if (card->use_mmio)
+               readw(card->ac97base_mmio);
+       else
+               inw(card->ac97base);
        if (ich_use_mmio(card)) {
                primary_codec_id = (int) readl(card->iobase_mmio + SDM) & 0x3;
                printk(KERN_INFO "i810_audio: Primary codec has ID %d\n",
@@ -2820,7 +2861,10 @@
                else 
                        printk("no response.\n");
        }
-       inw(card->ac97base);
+       if (card->use_mmio)
+               readw(card->ac97base_mmio);
+       else
+               inw(card->ac97base);
        return 1;
 }
 
@@ -2845,15 +2889,15 @@
        /* to check....                                         */
 
        card->channels = 2;
-       reg = inl(card->iobase + GLOB_STA);
+       reg = I810_IOREADL(card, GLOB_STA);
        if ( reg & 0x0200000 )
                card->channels = 6;
        else if ( reg & 0x0100000 )
                card->channels = 4;
        printk(KERN_INFO "i810_audio: Audio Controller supports %d 
channels.\n", card->channels);
        printk(KERN_INFO "i810_audio: Defaulting to base 2 channel mode.\n");
-       reg = inl(card->iobase + GLOB_CNT);
-       outl(reg & 0xffcfffff, card->iobase + GLOB_CNT);
+       reg = I810_IOREADL(card, GLOB_CNT);
+       I810_IOWRITEL(reg & 0xffcfffff, card, GLOB_CNT);
                
        for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) 
                card->ac97_codec[num_ac97] = NULL;
@@ -2864,8 +2908,10 @@
        for (num_ac97 = 0; num_ac97 < nr_ac97_max; num_ac97++) {
                /* codec reset */
                printk(KERN_INFO "i810_audio: Resetting connection %d\n", 
num_ac97);
-               if (card->use_mmio) readw(card->ac97base_mmio + 0x80*num_ac97);
-               else inw(card->ac97base + 0x80*num_ac97);
+               if (card->use_mmio)
+                       readw(card->ac97base_mmio + 0x80*num_ac97);
+               else
+                       inw(card->ac97base + 0x80*num_ac97);
 
                /* If we have the SDATA_IN Map Register, as on ICH4, we
                   do not loop thru all possible codec IDs but thru all 
@@ -3068,7 +3114,7 @@
                        goto config_out;
                }
                dmabuf->count = dmabuf->dmasize;
-               CIV_TO_LVI(card->iobase+dmabuf->write_channel->port, -1);
+               CIV_TO_LVI(card, dmabuf->write_channel->port, -1);
                local_irq_save(flags);
                start_dac(state);
                offset = i810_get_dma_addr(state, 0);
@@ -3112,13 +3158,6 @@
                return -ENODEV;
        }
        
-       if( pci_resource_start(pci_dev, 1) == 0)
-       {
-               /* MMIO only ICH5 .. here be dragons .. */
-               printk(KERN_ERR "i810_audio: Pure MMIO interfaces not yet 
supported.\n");
-               return -ENODEV;
-       }
-
        if ((card = kmalloc(sizeof(struct i810_card), GFP_KERNEL)) == NULL) {
                printk(KERN_ERR "i810_audio: out of memory\n");
                return -ENOMEM;
@@ -3131,6 +3170,11 @@
        card->ac97base = pci_resource_start (pci_dev, 0);
        card->iobase = pci_resource_start (pci_dev, 1);
 
+       if (!(card->ac97base) || !(card->iobase)) {
+               card->ac97base = 0;
+               card->iobase = 0;
+       }
+
        /* if chipset could have mmio capability, check it */ 
        if (card_cap[pci_id->driver_data].flags & CAP_MMIO) {
                card->ac97base_mmio_phys = pci_resource_start (pci_dev, 2);
@@ -3145,6 +3189,11 @@
                }
        }
 
+       if (!(card->use_mmio) && (!(card->iobase) || !(card->ac97base))) {
+               printk(KERN_ERR "i810_audio: No I/O resources available.\n");
+               goto out_mem;
+       }
+
        card->irq = pci_dev->irq;
        card->next = devs;
        card->magic = I810_CARD_MAGIC;
@@ -3190,8 +3239,14 @@
        }
 
        /* claim our iospace and irq */
-       request_region(card->iobase, 64, card_names[pci_id->driver_data]);
-       request_region(card->ac97base, 256, card_names[pci_id->driver_data]);
+       if (!request_region(card->iobase, 64, card_names[pci_id->driver_data])) 
{
+               printk(KERN_ERR "i810_audio: unable to allocate region %lx\n", 
card->iobase);
+               goto out_region1;
+       }
+       if (!request_region(card->ac97base, 256, 
card_names[pci_id->driver_data])) {
+               printk(KERN_ERR "i810_audio: unable to allocate region %lx\n", 
card->ac97base);
+               goto out_region2;
+       }
 
        if (request_irq(card->irq, &i810_interrupt, SA_SHIRQ,
                        card_names[pci_id->driver_data], card)) {
@@ -3264,8 +3319,10 @@
                release_mem_region(card->iobase_mmio_phys, 256);
        }
 out_pio:       
-       release_region(card->iobase, 64);
        release_region(card->ac97base, 256);
+out_region2:
+       release_region(card->iobase, 64);
+out_region1:
        pci_free_consistent(pci_dev, sizeof(struct i810_channel)*NR_HW_CH,
            card->channel, card->chandma);
 out_mem:
diff -urN linux/drivers/sound/.indent.pro linux/drivers/sound/.indent.pro
--- linux/drivers/sound/Attic/.indent.pro       2005-09-23 21:41:25.216730000 
+0100     1.1.1.1
+++ linux/drivers/sound/Attic/.indent.pro       1970/01/01 00:00:00+0100
@@ -1,8 +0,0 @@
--bad 
--bap 
--nfca
--bl 
--psl 
--di16
--lp
--ip5
diff -urN linux/drivers/sound/.version linux/drivers/sound/.version
--- linux/drivers/sound/Attic/.version  2005-09-23 21:41:25.241618000 +0100     
1.3
+++ linux/drivers/sound/Attic/.version  1970/01/01 00:00:00+0100
@@ -1,2 +0,0 @@
-3.8s
-0x030804
diff -urN linux/drivers/usb/printer.c linux/drivers/usb/printer.c
--- linux/drivers/usb/Attic/printer.c   2004/08/14 18:38:56     1.37.2.7
+++ linux/drivers/usb/Attic/printer.c   2005/09/23 20:41:25     1.37.2.8
@@ -740,6 +740,7 @@
                                schedule();
                        } else {
                                set_current_state(TASK_RUNNING);
+                               down (&usblp->sem);
                                break;
                        }
                        down (&usblp->sem);
diff -urN linux/drivers/usb/gadget/file_storage.c 
linux/drivers/usb/gadget/file_storage.c
--- linux/drivers/usb/gadget/file_storage.c     2004/08/14 18:38:56     1.2.2.2
+++ linux/drivers/usb/gadget/file_storage.c     2005/09/23 20:41:25     1.2.2.3
@@ -1454,6 +1454,7 @@
        /* Respond with data/status or defer until later? */
        if (rc >= 0 && rc != DELAYED_STATUS) {
                fsg->ep0req->length = rc;
+               fsg->ep0req->zero = (rc < ctrl->wLength);
                fsg->ep0req_name = (ctrl->bRequestType & USB_DIR_IN ?
                                "ep0-in" : "ep0-out");
                rc = ep0_queue(fsg);
diff -urN linux/drivers/usb/serial/ftdi_sio.c 
linux/drivers/usb/serial/ftdi_sio.c
--- linux/drivers/usb/serial/ftdi_sio.c 2005/03/18 12:13:29     1.21.2.12
+++ linux/drivers/usb/serial/ftdi_sio.c 2005/09/23 20:41:25     1.21.2.13
@@ -350,6 +350,17 @@
        { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_3, 0, 0x3ff) },
        { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_4, 0, 0x3ff) },
        { USB_DEVICE_VER(FTDI_VID, FTDI_ELV_UO100_PID, 0, 0x3ff) },
+       { USB_DEVICE_VER(FTDI_VID, FTDI_ELV_UM100_PID, 0, 0x3ff) },
+       { USB_DEVICE_VER(FTDI_VID, INSIDE_ACCESSO, 0, 0x3ff) },
+       { USB_DEVICE_VER(INTREPID_VID, INTREPID_VALUECAN_PID, 0, 0x3ff) },
+       { USB_DEVICE_VER(INTREPID_VID, INTREPID_NEOVI_PID, 0, 0x3ff) },
+       { USB_DEVICE_VER(FALCOM_VID, FALCOM_TWIST_PID, 0, 0x3ff) },
+       { USB_DEVICE_VER(FTDI_VID, FTDI_SUUNTO_SPORTS_PID, 0, 0x3ff) },
+       { USB_DEVICE_VER(FTDI_VID, FTDI_RM_CANVIEW_PID, 0, 0x3ff) },
+       { USB_DEVICE_VER(BANDB_VID, BANDB_USOTL4_PID, 0, 0x3ff) },
+       { USB_DEVICE_VER(BANDB_VID, BANDB_USTL4_PID, 0, 0x3ff) },
+       { USB_DEVICE_VER(BANDB_VID, BANDB_USO9ML2_PID, 0, 0x3ff) },
+       { USB_DEVICE_VER(FTDI_VID, EVER_ECO_PRO_CDS, 0, 0x3ff) },
        { }                                             /* Terminating entry */
 };
 
@@ -378,6 +389,7 @@
        { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_5_PID, 0x400, 0xffff) },
        { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_6_PID, 0x400, 0xffff) },
        { USB_DEVICE_VER(FTDI_VID, FTDI_PERLE_ULTRAPORT_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(FTDI_VID, FTDI_PIEGROUP_PID, 0x400, 0xffff) },
        { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2101_PID, 0x400, 0xffff) },
        { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2102_PID, 0x400, 0xffff) },
        { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2103_PID, 0x400, 0xffff) },
@@ -430,9 +442,41 @@
        { USB_DEVICE_VER(FTDI_VID, PROTEGO_R2X0, 0x400, 0xffff) },
        { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_3, 0x400, 0xffff) },
        { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_4, 0x400, 0xffff) },
+       { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E808_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E809_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80A_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80B_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80C_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80D_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80E_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80F_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E888_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E889_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88A_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88B_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88C_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88D_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88E_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88F_PID, 0x400, 0xffff) },
        { USB_DEVICE_VER(FTDI_VID, FTDI_ELV_UO100_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(FTDI_VID, FTDI_ELV_UM100_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(FTDI_VID, LINX_SDMUSBQSS_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(FTDI_VID, LINX_MASTERDEVEL2_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_0_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_1_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_2_PID, 0x400, 0xffff) },
        { USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) },
+       { USB_DEVICE_VER(FTDI_VID, INSIDE_ACCESSO, 0x400, 0xffff) },
+       { USB_DEVICE_VER(INTREPID_VID, INTREPID_VALUECAN_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(INTREPID_VID, INTREPID_NEOVI_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(FALCOM_VID, FALCOM_TWIST_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(FTDI_VID, FTDI_SUUNTO_SPORTS_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(FTDI_VID, FTDI_RM_CANVIEW_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(BANDB_VID, BANDB_USOTL4_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(BANDB_VID, BANDB_USTL4_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(BANDB_VID, BANDB_USO9ML2_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(FTDI_VID, EVER_ECO_PRO_CDS, 0x400, 0xffff) },
        { }                                             /* Terminating entry */
 };
 
@@ -482,6 +526,7 @@
        { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_5_PID, 0x400, 0xffff) },
        { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_6_PID, 0x400, 0xffff) },
        { USB_DEVICE_VER(FTDI_VID, FTDI_PERLE_ULTRAPORT_PID, 0x400, 0xffff) },
+       { USB_DEVICE(FTDI_VID, FTDI_PIEGROUP_PID) },
        { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2101_PID) },
        { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2102_PID) },
        { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2103_PID) },
@@ -536,9 +581,41 @@
        { USB_DEVICE(FTDI_VID, PROTEGO_R2X0) },
        { USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_3) },
        { USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_4) },
+       { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E808_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E809_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80A_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80B_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80C_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80D_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80E_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80F_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E888_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E889_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88A_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88B_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88C_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88D_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88E_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88F_PID, 0x400, 0xffff) },
        { USB_DEVICE(FTDI_VID, FTDI_ELV_UO100_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_UM100_PID) },
+       { USB_DEVICE_VER(FTDI_VID, LINX_SDMUSBQSS_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(FTDI_VID, LINX_MASTERDEVEL2_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_0_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_1_PID, 0x400, 0xffff) },
+       { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_2_PID, 0x400, 0xffff) },
        { USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) },
+       { USB_DEVICE(FTDI_VID, INSIDE_ACCESSO) },
+       { USB_DEVICE(INTREPID_VID, INTREPID_VALUECAN_PID) },
+       { USB_DEVICE(INTREPID_VID, INTREPID_NEOVI_PID) },
+       { USB_DEVICE(FALCOM_VID, FALCOM_TWIST_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_SUUNTO_SPORTS_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_RM_CANVIEW_PID) },
+       { USB_DEVICE(BANDB_VID, BANDB_USOTL4_PID) },
+       { USB_DEVICE(BANDB_VID, BANDB_USTL4_PID) },
+       { USB_DEVICE(BANDB_VID, BANDB_USO9ML2_PID) },
+       { USB_DEVICE(FTDI_VID, EVER_ECO_PRO_CDS) },
        { }                                             /* Terminating entry */
 };
 
@@ -1012,7 +1089,7 @@
                goto check_and_exit;
        }
 
-       if ((new_serial.baud_base != priv->baud_base) ||
+       if ((new_serial.baud_base != priv->baud_base) &&
            (new_serial.baud_base < 9600))
                return -EINVAL;
 
@@ -1238,25 +1315,23 @@
 } /* ftdi_HE_TIRA1_startup */
 
 
-/* Startup for the 8U232AM chip */
+/* Startup for user specified 8U232AM (or 232BM) device */
 static int ftdi_userdev_startup (struct usb_serial *serial)
 {
        struct ftdi_private *priv;
+       int err;
 
-       priv = serial->port->private = kmalloc(sizeof(struct ftdi_private), 
GFP_KERNEL);
-       if (!priv){
-               err("%s- kmalloc(%Zd) failed.", __FUNCTION__, sizeof(struct 
ftdi_private));
-               return -ENOMEM;
+
+       dbg("%s",__FUNCTION__);
+       /* XXX Assume it's a FT8U232AM.  An FT232BM device can be used, but
+        * it will behave like a FT8U232AM.  -- IJA */
+       err = ftdi_8U232AM_startup(serial);
+       if (err){
+               return (err);
        }
 
-       priv->chip_type = FT8U232AM; /* XXX: Hmm. Keep this.... -- REW */
+       priv = serial->port->private;
        priv->baud_base = baud_base; 
-       priv->custom_divisor = 0;
-       priv->write_offset = 0;
-        init_waitqueue_head(&priv->delta_msr_wait);
-       /* This will push the characters through immediately rather
-          than queue a task to deliver them */
-       priv->flags = ASYNC_LOW_LATENCY;
        
        return (0);
 }
@@ -1451,7 +1526,7 @@
        dbg("%s port %d, %d bytes", __FUNCTION__, port->number, count);
 
        if (count == 0) {
-               err("write request of 0 bytes");
+               dbg("write request of 0 bytes");
                goto exit;
        }
        
@@ -1585,17 +1660,18 @@
        int i;
        unsigned long flags;
 
-
        spin_lock_irqsave (&priv->write_urb_pool_lock, flags);
-
        for (i = 0; i < NUM_URBS && priv->write_urb_pool[i]; i++) {
-               if (priv->write_urb_pool[i]->status != -EINPROGRESS) {
-                       room += URB_TRANSFER_BUFFER_SIZE - priv->write_offset;
-               }
+               if (priv->write_urb_pool[i]->status != -EINPROGRESS)
+                       room++;
        }
-       
        spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags);
 
+       /* Harmless lies for the sake of line disciplines */
+       if ((room -= 2) < 0)
+               room = 0;
+
+       room *= URB_TRANSFER_BUFFER_SIZE - priv->write_offset;
        dbg("%s - returns %d", __FUNCTION__, room);     
        return(room);
 } /* ftdi_write_room */
@@ -1913,6 +1989,13 @@
                if (change_speed(port)) {
                        err("%s urb failed to set baurdrate", __FUNCTION__);
                }
+               /* Ensure  RTS and DTR are raised */
+               else if (set_dtr(port, HIGH) < 0){
+                       err("%s Error from DTR HIGH urb", __FUNCTION__);
+               }
+               else if (set_rts(port, HIGH) < 0){
+                       err("%s Error from RTS HIGH urb", __FUNCTION__);
+               }
        }
 
        /* Set flow control */
@@ -2209,6 +2292,8 @@
 
        dbg("%s", __FUNCTION__);
 
+       if (vendor != -1)
+               usb_serial_deregister (&ftdi_userdev_device);
        usb_serial_deregister (&ftdi_HE_TIRA1_device);
        usb_serial_deregister (&ftdi_USB_UIRT_device);
        usb_serial_deregister (&ftdi_FT232BM_device);
diff -urN linux/drivers/usb/serial/ftdi_sio.h 
linux/drivers/usb/serial/ftdi_sio.h
--- linux/drivers/usb/serial/ftdi_sio.h 2004/08/14 18:38:56     1.4.2.9
+++ linux/drivers/usb/serial/ftdi_sio.h 2005/09/23 20:41:25     1.4.2.10
@@ -143,6 +143,8 @@
 
 /* ELV USB Module UO100 (PID sent by Stefan Frings) */
 #define FTDI_ELV_UO100_PID     0xFB58  /* Product Id */
+/* ELV USB Module UM100 (PID sent by Arnim Laeuger) */
+#define FTDI_ELV_UM100_PID     0xFB5A  /* Product Id */
 
 /*
  * Definitions for ID TECH (www.idt-net.com) devices
@@ -155,8 +157,13 @@
  */
 #define OCT_VID                        0x0B39  /* OCT vendor ID */
 /* Note: OCT US101 is also rebadged as Dick Smith Electronics (NZ) XH6381 */
+/* Also rebadged as Dick Smith Electronics (Aus) XH6451 */
+/* Also rebadged as SIIG Inc. model US2308 hardware version 1 */
 #define OCT_US101_PID          0x0421  /* OCT US101 USB to RS-232 */
 
+/* an infrared receiver for user access control with IR tags */
+#define FTDI_PIEGROUP_PID      0xF208  /* Product Id */
+
 /*
  * Protego product ids
  */
@@ -165,11 +172,81 @@
 #define PROTEGO_SPECIAL_3      0xFC72  /* special/unknown device */
 #define PROTEGO_SPECIAL_4      0xFC73  /* special/unknown device */ 
 
+/*
+ * Gude Analog- und Digitalsysteme GmbH
+ */
+#define FTDI_GUDEADS_E808_PID    0xE808
+#define FTDI_GUDEADS_E809_PID    0xE809
+#define FTDI_GUDEADS_E80A_PID    0xE80A
+#define FTDI_GUDEADS_E80B_PID    0xE80B
+#define FTDI_GUDEADS_E80C_PID    0xE80C
+#define FTDI_GUDEADS_E80D_PID    0xE80D
+#define FTDI_GUDEADS_E80E_PID    0xE80E
+#define FTDI_GUDEADS_E80F_PID    0xE80F
+#define FTDI_GUDEADS_E888_PID    0xE888  /* Expert ISDN Control USB */
+#define FTDI_GUDEADS_E889_PID    0xE889  /* USB RS-232 OptoBridge */
+#define FTDI_GUDEADS_E88A_PID    0xE88A
+#define FTDI_GUDEADS_E88B_PID    0xE88B
+#define FTDI_GUDEADS_E88C_PID    0xE88C
+#define FTDI_GUDEADS_E88D_PID    0xE88D
+#define FTDI_GUDEADS_E88E_PID    0xE88E
+#define FTDI_GUDEADS_E88F_PID    0xE88F
+
+/*
+ * Linx Technologies product ids
+ */
+#define LINX_SDMUSBQSS_PID     0xF448  /* Linx SDM-USB-QS-S */
+#define LINX_MASTERDEVEL2_PID   0xF449   /* Linx Master Development 2.0 */
+#define LINX_FUTURE_0_PID   0xF44A   /* Linx future device */
+#define LINX_FUTURE_1_PID   0xF44B   /* Linx future device */
+#define LINX_FUTURE_2_PID   0xF44C   /* Linx future device */
+
 /* CCS Inc. ICDU/ICDU40 product ID - the FT232BM is used in an 
in-circuit-debugger */
 /* unit for PIC16's/PIC18's */
 #define FTDI_CCSICDU20_0_PID  0xF9D0     
 #define FTDI_CCSICDU40_1_PID  0xF9D1     
 
+/* Inside Accesso contactless reader (http://www.insidefr.com) */
+#define INSIDE_ACCESSO         0xFAD0
+
+/*
+ * Intrepid Control Systems (http://www.intrepidcs.com/) ValueCAN and NeoVI
+ */
+#define INTREPID_VID           0x093C
+#define INTREPID_VALUECAN_PID  0x0601
+#define INTREPID_NEOVI_PID     0x0701
+
+/*
+ * Falcom Wireless Communications GmbH
+ */
+#define FALCOM_VID             0x0F94  /* Vendor Id */
+#define FALCOM_TWIST_PID       0x0001  /* Falcom Twist USB GPRS modem */
+
+/*
+ * SUUNTO product ids
+ */
+#define FTDI_SUUNTO_SPORTS_PID 0xF680  /* Suunto Sports instrument */
+
+/*
+ * Definitions for B&B Electronics products.
+ */
+#define BANDB_VID              0x0856  /* B&B Electronics Vendor ID */
+#define BANDB_USOTL4_PID       0xAC01  /* USOTL4 Isolated RS-485 Converter */
+#define BANDB_USTL4_PID                0xAC02  /* USTL4 RS-485 Converter */
+#define BANDB_USO9ML2_PID      0xAC03  /* USO9ML2 Isolated RS-232 Converter */
+
+/*
+ * RM Michaelides CANview USB (http://www.rmcan.com)
+ * CAN fieldbus interface adapter, added by port GmbH www.port.de).
+ * Ian Abbott changed the macro names for consistency.
+ */
+#define FTDI_RM_CANVIEW_PID    0xfd60  /* Product Id */
+
+/*
+ * EVER Eco Pro UPS (http://www.ever.com.pl/)
+ */
+#define        EVER_ECO_PRO_CDS        0xe520  /* RS-232 converter */
+
 /* Commands */
 #define FTDI_SIO_RESET                 0 /* Reset the port */
 #define FTDI_SIO_MODEM_CTRL    1 /* Set the modem control register */
diff -urN linux/fs/buffer.c linux/fs/buffer.c
--- linux/fs/buffer.c   2004/11/19 00:28:47     1.75.2.14
+++ linux/fs/buffer.c   2005/09/23 20:41:25     1.75.2.15
@@ -584,7 +584,7 @@
        (*bhp)->b_prev_free->b_next_free = bh;
        (*bhp)->b_prev_free = bh;
        nr_buffers_type[blist]++;
-       size_buffers_type[blist] += bh->b_size;
+       size_buffers_type[blist] += bh->b_size >> 9;
 }
 
 static void __remove_from_lru_list(struct buffer_head * bh)
@@ -604,7 +604,7 @@
                bh->b_next_free = NULL;
                bh->b_prev_free = NULL;
                nr_buffers_type[blist]--;
-               size_buffers_type[blist] -= bh->b_size;
+               size_buffers_type[blist] -= bh->b_size >> 9;
        }
 }
 
@@ -1033,7 +1033,7 @@
 {
        unsigned long dirty, tot, hard_dirty_limit, soft_dirty_limit;
 
-       dirty = size_buffers_type[BUF_DIRTY] >> PAGE_SHIFT;
+       dirty = size_buffers_type[BUF_DIRTY] >> (PAGE_SHIFT - 9);
        tot = nr_free_buffer_pages();
 
        dirty *= 100;
@@ -1054,7 +1054,7 @@
 {
        unsigned long dirty, tot, dirty_limit;
 
-       dirty = size_buffers_type[BUF_DIRTY] >> PAGE_SHIFT;
+       dirty = size_buffers_type[BUF_DIRTY] >> (PAGE_SHIFT - 9);
        tot = nr_free_buffer_pages();
 
        dirty *= 100;
@@ -2839,7 +2839,7 @@
                }
                printk("%9s: %d buffers, %lu kbyte, %d used (last=%d), "
                       "%d locked, %d dirty, %d delay\n",
-                      buf_types[nlist], found, size_buffers_type[nlist]>>10,
+                      buf_types[nlist], found, 
size_buffers_type[nlist]>>(10-9),
                       used, lastused, locked, dirty, delalloc);
        }
        spin_unlock(&lru_list_lock);
diff -urN linux/fs/inode.c linux/fs/inode.c
--- linux/fs/inode.c    2004/04/16 03:14:19     1.57.2.11
+++ linux/fs/inode.c    2005/09/23 20:41:26     1.57.2.12
@@ -297,7 +297,7 @@
 {
        struct list_head *to;
 
-       if (inode->i_state & I_FREEING)
+       if (inode->i_state & (I_FREEING|I_CLEAR))
                return;
        if (list_empty(&inode->i_hash))
                return;
@@ -634,7 +634,9 @@
                cdput(inode->i_cdev);
                inode->i_cdev = NULL;
        }
+       spin_lock(&inode_lock);
        inode->i_state = I_CLEAR;
+       spin_unlock(&inode_lock);
 }
 
 /*
diff -urN linux/fs/isofs/compress.c linux/fs/isofs/compress.c
--- linux/fs/isofs/compress.c   2002/09/11 12:45:23     1.2.2.1
+++ linux/fs/isofs/compress.c   2005/09/23 20:41:26     1.2.2.2
@@ -147,8 +147,14 @@
        cend = le32_to_cpu(*(u32 *)(bh->b_data + (blockendptr & bufmask)));
        brelse(bh);
 
+       if (cstart > cend)
+               goto eio;
+
        csize = cend-cstart;
 
+       if (csize > deflateBound(1UL << zisofs_block_shift))
+               goto eio;
+
        /* Now page[] contains an array of pages, any of which can be NULL,
           and the locks on which we hold.  We should now read the data and
           release the pages.  If the pages are NULL the decompressed data
diff -urN linux/fs/isofs/inode.c linux/fs/isofs/inode.c
--- linux/fs/isofs/inode.c      2005/04/05 19:09:57     1.39.2.4
+++ linux/fs/isofs/inode.c      2005/09/23 20:41:26     1.39.2.5
@@ -335,16 +335,16 @@
                        else if (!strcmp(value,"acorn")) popt->map = 'a';
                        else return 0;
                }
-               if (!strcmp(this_char,"session") && value) {
+               else if (!strcmp(this_char,"session") && value) {
                        char * vpnt = value;
                        unsigned int ivalue = simple_strtoul(vpnt, &vpnt, 0);
-                       if(ivalue < 0 || ivalue >99) return 0;
+                       if (ivalue > 99) return 0;
                        popt->session=ivalue+1;
                }
-               if (!strcmp(this_char,"sbsector") && value) {
+               else if (!strcmp(this_char,"sbsector") && value) {
                        char * vpnt = value;
                        unsigned int ivalue = simple_strtoul(vpnt, &vpnt, 0);
-                       if(ivalue < 0 || ivalue >660*512) return 0;
+                       if (ivalue > 660*512) return 0;
                        popt->sbsector=ivalue;
                }
                else if (!strcmp(this_char,"check") && value) {
diff -urN linux/fs/nfs/nfs2xdr.c linux/fs/nfs/nfs2xdr.c
--- linux/fs/nfs/nfs2xdr.c      2003/01/11 17:53:17     1.13.2.3
+++ linux/fs/nfs/nfs2xdr.c      2005/09/23 20:41:26     1.13.2.4
@@ -571,8 +571,11 @@
        strlen = (u32*)kmap(rcvbuf->pages[0]);
        /* Convert length of symlink */
        len = ntohl(*strlen);
-       if (len > rcvbuf->page_len)
-               len = rcvbuf->page_len;
+       if (len >= rcvbuf->page_len - sizeof(u32) || len > NFS2_MAXPATHLEN) {
+               dprintk("NFS: server returned giant symlink!\n");
+               kunmap(rcvbuf->pages[0]);
+               return -ENAMETOOLONG;
+        }
        *strlen = len;
        /* NULL terminate the string we got */
        string = (char *)(strlen + 1);
diff -urN linux/fs/nfs/nfs3xdr.c linux/fs/nfs/nfs3xdr.c
--- linux/fs/nfs/nfs3xdr.c      2003/11/17 01:07:44     1.8.2.3
+++ linux/fs/nfs/nfs3xdr.c      2005/09/23 20:41:26     1.8.2.4
@@ -759,8 +759,11 @@
        strlen = (u32*)kmap(rcvbuf->pages[0]);
        /* Convert length of symlink */
        len = ntohl(*strlen);
-       if (len > rcvbuf->page_len)
-               len = rcvbuf->page_len;
+       if (len >= rcvbuf->page_len - sizeof(u32)) {
+               dprintk("NFS: server returned giant symlink!\n");
+               kunmap(rcvbuf->pages[0]);
+               return -ENAMETOOLONG;
+        }
        *strlen = len;
        /* NULL terminate the string we got */
        string = (char *)(strlen + 1);
diff -urN linux/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c
--- linux/fs/nfsd/vfs.c 2005/03/18 12:13:30     1.50.2.10
+++ linux/fs/nfsd/vfs.c 2005/09/23 20:41:26     1.50.2.11
@@ -280,13 +280,17 @@
        }
 
        /* Revoke setuid/setgid bit on chown/chgrp */
-       if ((iap->ia_valid & ATTR_UID) && (imode & S_ISUID)
-        && iap->ia_uid != inode->i_uid) {
+       if ((iap->ia_valid & ATTR_UID)
+           && (imode & S_ISUID)
+           && !S_ISDIR(imode)
+           && iap->ia_uid != inode->i_uid) {
                iap->ia_valid |= ATTR_MODE;
                iap->ia_mode = imode &= ~S_ISUID;
        }
-       if ((iap->ia_valid & ATTR_GID) && (imode & S_ISGID)
-        && iap->ia_gid != inode->i_gid) {
+       if ((iap->ia_valid & ATTR_GID)
+           && (imode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)
+           && !S_ISDIR(imode)
+           && iap->ia_gid != inode->i_gid) {
                iap->ia_valid |= ATTR_MODE;
                iap->ia_mode = imode &= ~S_ISGID;
        }
@@ -297,6 +301,7 @@
        iap->ia_valid |= ATTR_CTIME;
 
        if (iap->ia_valid & ATTR_SIZE) {
+               down_write(&inode->i_alloc_sem);
                fh_lock(fhp);
                size_change = 1;
        }
@@ -307,6 +312,7 @@
        }
        if (size_change) {
                fh_unlock(fhp);
+               up_write(&inode->i_alloc_sem);
                put_write_access(inode);
        }
        if (!err)
diff -urN linux/include/asm-i386/system.h linux/include/asm-i386/system.h
--- linux/include/asm-i386/system.h     2004/04/16 03:14:20     1.26.2.5
+++ linux/include/asm-i386/system.h     2005/09/23 20:41:27     1.26.2.6
@@ -84,7 +84,7 @@
 #define loadsegment(seg,value)                 \
        asm volatile("\n"                       \
                "1:\t"                          \
-               "movl %0,%%" #seg "\n"          \
+               "mov %0,%%" #seg "\n"           \
                "2:\n"                          \
                ".section .fixup,\"ax\"\n"      \
                "3:\t"                          \
@@ -96,7 +96,7 @@
                ".align 4\n\t"                  \
                ".long 1b,3b\n"                 \
                ".previous"                     \
-               : :"m" (*(unsigned int *)&(value)))
+               : :"m" (value))
 
 /*
  * Clear and set 'TS' bit respectively
diff -urN linux/include/asm-sparc64/uaccess.h 
linux/include/asm-sparc64/uaccess.h
--- linux/include/asm-sparc64/uaccess.h 2004/11/19 00:28:51     1.14.2.1
+++ linux/include/asm-sparc64/uaccess.h 2005/09/23 20:41:27     1.14.2.2
@@ -294,10 +294,10 @@
 }
 #define __copy_in_user copy_in_user
 
+extern __kernel_size_t __bzero_noasi(void *addr, __kernel_size_t size);
+       
 extern __inline__ __kernel_size_t __clear_user(void *addr, __kernel_size_t 
size)
 {
-       extern __kernel_size_t __bzero_noasi(void *addr, __kernel_size_t size);
-       
        return __bzero_noasi(addr, size);
 }
 
diff -urN linux/include/asm-x86_64/desc.h linux/include/asm-x86_64/desc.h
--- linux/include/asm-x86_64/desc.h     2004/08/14 18:39:03     1.2.2.5
+++ linux/include/asm-x86_64/desc.h     2005/09/23 20:41:27     1.2.2.6
@@ -128,7 +128,7 @@
 
 static inline void set_tss_desc(unsigned n, void *addr)
 { 
-       set_tssldt_descriptor((void *)&gdt_table + __CPU_DESC_INDEX(n,tss), 
(unsigned long)addr, DESC_TSS, sizeof(struct tss_struct)); 
+       set_tssldt_descriptor((void *)&gdt_table + __CPU_DESC_INDEX(n,tss), 
(unsigned long)addr, DESC_TSS, IO_BITMAP_OFFSET + IO_BITMAP_BYTES + 7); 
 } 
 
 static inline void set_ldt_desc(unsigned n, void *addr, int size)
diff -urN linux/include/asm-x86_64/pci.h linux/include/asm-x86_64/pci.h
--- linux/include/asm-x86_64/pci.h      2004/04/16 03:14:20     1.1.2.7
+++ linux/include/asm-x86_64/pci.h      2005/09/23 20:41:27     1.1.2.8
@@ -65,8 +65,9 @@
 extern void pci_free_consistent(struct pci_dev *hwdev, size_t size,
                                void *vaddr, dma_addr_t dma_handle);
 
-#ifdef CONFIG_SWIOTLB
 extern int swiotlb; 
+
+#ifdef CONFIG_SWIOTLB
 extern dma_addr_t swiotlb_map_single (struct pci_dev *hwdev, void *ptr, size_t 
size, 
                                      int dir);
 extern void swiotlb_unmap_single (struct pci_dev *hwdev, dma_addr_t dev_addr,
diff -urN linux/include/asm-x86_64/processor.h 
linux/include/asm-x86_64/processor.h
--- linux/include/asm-x86_64/processor.h        2004/04/16 03:14:20     1.3.2.6
+++ linux/include/asm-x86_64/processor.h        2005/09/23 20:41:27     1.3.2.7
@@ -260,6 +260,7 @@
  * Size of io_bitmap in longwords: 32 is ports 0-0x3ff.
  */
 #define IO_BITMAP_SIZE 32
+#define IO_BITMAP_BYTES (IO_BITMAP_SIZE * sizeof(u32))
 #define IO_BITMAP_OFFSET offsetof(struct tss_struct,io_bitmap)
 #define INVALID_IO_BITMAP_OFFSET 0x8000
 
@@ -325,10 +326,9 @@
 #define INIT_MMAP \
 { &init_mm, 0, 0, NULL, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, 1, NULL, 
NULL }
 
-#define STACKFAULT_STACK 1
-#define DOUBLEFAULT_STACK 2 
-#define NMI_STACK 3 
-#define N_EXCEPTION_STACKS 3  /* hw limit: 7 */
+#define DOUBLEFAULT_STACK 1
+#define NMI_STACK 2
+#define N_EXCEPTION_STACKS 2  /* hw limit: 7 */
 #define EXCEPTION_STKSZ PAGE_SIZE
 #define EXCEPTION_STK_ORDER 0
 
diff -urN linux/include/linux/ata.h linux/include/linux/ata.h
--- linux/include/linux/ata.h   2005/03/18 12:13:31     1.6.2.4
+++ linux/include/linux/ata.h   2005/09/23 20:41:27     1.6.2.5
@@ -224,6 +224,7 @@
 };
 
 #define ata_id_is_ata(id)      (((id)[0] & (1 << 15)) == 0)
+#define ata_id_is_sata(id)     ((id)[93] == 0)
 #define ata_id_rahead_enabled(id) ((id)[85] & (1 << 6))
 #define ata_id_wcache_enabled(id) ((id)[85] & (1 << 5))
 #define ata_id_has_flush(id) ((id)[83] & (1 << 12))
diff -urN linux/include/linux/libata-compat.h 
linux/include/linux/libata-compat.h
--- linux/include/linux/Attic/libata-compat.h   2005/03/18 12:13:31     1.1.2.3
+++ linux/include/linux/Attic/libata-compat.h   2005/09/23 20:41:27     1.1.2.4
@@ -23,6 +23,9 @@
        return (struct pci_dev *) dev;
 }
 
+static inline int pci_enable_msi(struct pci_dev *dev) { return -1; }
+static inline void pci_disable_msi(struct pci_dev *dev) {}
+
 #define pci_set_consistent_dma_mask(pdev,mask) (0)
 
 #define DMA_FROM_DEVICE PCI_DMA_FROMDEVICE
diff -urN linux/include/linux/libata.h linux/include/linux/libata.h
--- linux/include/linux/libata.h        2005/03/18 12:13:31     1.11.2.6
+++ linux/include/linux/libata.h        2005/09/23 20:41:27     1.11.2.7
@@ -411,6 +411,7 @@
 extern void ata_exec_command(struct ata_port *ap, struct ata_taskfile *tf);
 extern int ata_port_start (struct ata_port *ap);
 extern void ata_port_stop (struct ata_port *ap);
+extern void ata_host_stop (struct ata_host_set *host_set);
 extern irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs 
*regs);
 extern void ata_qc_prep(struct ata_queued_cmd *qc);
 extern int ata_qc_issue_prot(struct ata_queued_cmd *qc);
@@ -421,6 +422,7 @@
 extern unsigned int ata_dev_classify(struct ata_taskfile *tf);
 extern void ata_dev_id_string(u16 *id, unsigned char *s,
                              unsigned int ofs, unsigned int len);
+extern void ata_dev_config(struct ata_port *ap, unsigned int i);
 extern void ata_bmdma_setup (struct ata_queued_cmd *qc);
 extern void ata_bmdma_start (struct ata_queued_cmd *qc);
 extern void ata_bmdma_stop(struct ata_port *ap);
@@ -465,12 +467,34 @@
        return ap->ops->check_status(ap);
 }
 
+
+/**
+ *     ata_pause - Flush writes and pause 400 nanoseconds.
+ *     @ap: Port to wait for.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
+
 static inline void ata_pause(struct ata_port *ap)
 {
        ata_altstatus(ap);
        ndelay(400);
 }
 
+
+/**
+ *     ata_busy_wait - Wait for a port status register
+ *     @ap: Port to wait for.
+ *
+ *     Waits up to max*10 microseconds for the selected bits in the port's
+ *     status register to be cleared.
+ *     Returns final value of status register.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
+
 static inline u8 ata_busy_wait(struct ata_port *ap, unsigned int bits,
                               unsigned int max)
 {
@@ -485,6 +509,18 @@
        return status;
 }
 
+
+/**
+ *     ata_wait_idle - Wait for a port to be idle.
+ *     @ap: Port to wait for.
+ *
+ *     Waits up to 10ms for port's BUSY and DRQ signals to clear.
+ *     Returns final value of status register.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
+
 static inline u8 ata_wait_idle(struct ata_port *ap)
 {
        u8 status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
@@ -523,6 +559,18 @@
                tf->device = ATA_DEVICE_OBS | ATA_DEV1;
 }
 
+
+/**
+ *     ata_irq_on - Enable interrupts on a port.
+ *     @ap: Port on which interrupts are enabled.
+ *
+ *     Enable interrupts on a legacy IDE device using MMIO or PIO,
+ *     wait for idle, clear any pending interrupts.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
+
 static inline u8 ata_irq_on(struct ata_port *ap)
 {
        struct ata_ioports *ioaddr = &ap->ioaddr;
@@ -542,6 +590,18 @@
        return tmp;
 }
 
+
+/**
+ *     ata_irq_ack - Acknowledge a device interrupt.
+ *     @ap: Port on which interrupts are enabled.
+ *
+ *     Wait up to 10 ms for legacy IDE device to become idle (BUSY
+ *     or BUSY+DRQ clear).  Obtain dma status and port status from
+ *     device.  Clear the interrupt.  Return port status.
+ *
+ *     LOCKING:
+ */
+
 static inline u8 ata_irq_ack(struct ata_port *ap, unsigned int chk_drq)
 {
        unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY;
@@ -583,6 +643,13 @@
        ap->ops->scr_write(ap, reg, val);
 }
 
+static inline void scr_write_flush(struct ata_port *ap, unsigned int reg, 
+                                  u32 val)
+{
+       ap->ops->scr_write(ap, reg, val);
+       (void) ap->ops->scr_read(ap, reg);
+}
+
 static inline unsigned int sata_dev_present(struct ata_port *ap)
 {
        return ((scr_read(ap, SCR_STATUS) & 0xf) == 0x3) ? 1 : 0;
diff -urN linux/include/linux/pci_ids.h linux/include/linux/pci_ids.h
--- linux/include/linux/pci_ids.h       2005/05/25 17:14:24     1.50.2.28
+++ linux/include/linux/pci_ids.h       2005/09/23 20:41:27     1.50.2.29
@@ -608,6 +608,10 @@
 #define PCI_DEVICE_ID_HP_PCIX_LBA      0x122e
 #define PCI_DEVICE_ID_HP_SX1000_IOC    0x127c
 #define PCI_DEVICE_ID_HP_CISS          0x3210
+#define PCI_DEVICE_ID_HP_CISSA         0x3220
+#define PCI_DEVICE_ID_HP_CISSB         0x3222
+#define PCI_DEVICE_ID_HP_CISSC         0x3230
+#define PCI_DEVICE_ID_HP_CISSD         0x3238
 
 #define PCI_VENDOR_ID_PCTECH           0x1042
 #define PCI_DEVICE_ID_PCTECH_RZ1000    0x1000
diff -urN linux/include/linux/zlib.h linux/include/linux/zlib.h
--- linux/include/linux/zlib.h  2002/09/11 12:45:40     1.1.2.1
+++ linux/include/linux/zlib.h  2005/09/23 20:41:27     1.1.2.2
@@ -516,6 +516,11 @@
    stream state was inconsistent (such as zalloc or state being NULL).
 */
 
+static inline unsigned long deflateBound(unsigned long s)
+{
+       return s + ((s + 7) >> 3) + ((s + 63) >> 6) + 11;
+}
+
 ZEXTERN int ZEXPORT zlib_deflateParams OF((z_streamp strm,
                                              int level,
                                              int strategy));
diff -urN linux/include/linux/netfilter_ipv4/ip_nat_rule.h 
linux/include/linux/netfilter_ipv4/ip_nat_rule.h
--- linux/include/linux/netfilter_ipv4/ip_nat_rule.h    2003/11/17 01:07:46     
1.1.4.2
+++ linux/include/linux/netfilter_ipv4/ip_nat_rule.h    2005/09/23 20:41:27     
1.1.4.3
@@ -19,5 +19,10 @@
 alloc_null_binding(struct ip_conntrack *conntrack,
                   struct ip_nat_info *info,
                   unsigned int hooknum);
+
+extern unsigned int
+alloc_null_binding_confirmed(struct ip_conntrack *conntrack,
+                            struct ip_nat_info *info,
+                            unsigned int hooknum);
 #endif
 #endif /* _IP_NAT_RULE_H */
diff -urN linux/include/linux/netfilter_ipv4/ip_tables.h 
linux/include/linux/netfilter_ipv4/ip_tables.h
--- linux/include/linux/netfilter_ipv4/ip_tables.h      2005/04/05 19:09:58     
1.6.2.3
+++ linux/include/linux/netfilter_ipv4/ip_tables.h      2005/09/23 20:41:27     
1.6.2.4
@@ -283,8 +283,6 @@
        struct ipt_entry entrytable[0];
 };
 
-extern struct semaphore ipt_mutex;
-
 /* Standard return verdict, or do jump. */
 #define IPT_STANDARD_TARGET ""
 /* Error verdict. */
diff -urN linux/include/net/ip6_fib.h linux/include/net/ip6_fib.h
--- linux/include/net/ip6_fib.h 2004/11/19 00:28:51     1.7.4.3
+++ linux/include/net/ip6_fib.h 2005/09/23 20:41:28     1.7.4.4
@@ -171,13 +171,16 @@
 
 extern int                     fib6_add(struct fib6_node *root,
                                         struct rt6_info *rt,
-                                        struct nlmsghdr *nlh);
+                                        struct nlmsghdr *nlh,
+                                        struct netlink_skb_parms *req);
 
 extern int                     fib6_del(struct rt6_info *rt,
-                                        struct nlmsghdr *nlh);
+                                        struct nlmsghdr *nlh,
+                                        struct netlink_skb_parms *req);
 
 extern void                    inet6_rt_notify(int event, struct rt6_info *rt,
-                                               struct nlmsghdr *nlh);
+                                               struct nlmsghdr *nlh,
+                                               struct netlink_skb_parms *req);
 
 extern void                    fib6_run_gc(unsigned long dummy);
 
diff -urN linux/include/net/ip6_route.h linux/include/net/ip6_route.h
--- linux/include/net/ip6_route.h       2003/07/05 03:23:47     1.8.4.1
+++ linux/include/net/ip6_route.h       2005/09/23 20:41:28     1.8.4.2
@@ -39,9 +39,11 @@
 extern int                     ipv6_route_ioctl(unsigned int cmd, void *arg);
 
 extern int                     ip6_route_add(struct in6_rtmsg *rtmsg,
-                                             struct nlmsghdr *);
+                                             struct nlmsghdr *,
+                                             struct netlink_skb_parms *req);
 extern int                     ip6_del_rt(struct rt6_info *,
-                                          struct nlmsghdr *);
+                                          struct nlmsghdr *,
+                                          struct netlink_skb_parms *req);
 
 extern int                     ip6_rt_addr_add(struct in6_addr *addr,
                                                struct net_device *dev);
diff -urN linux/lib/inflate.c linux/lib/inflate.c
--- linux/lib/inflate.c 2002/09/11 12:45:42     1.5.2.1
+++ linux/lib/inflate.c 2005/09/23 20:41:28     1.5.2.2
@@ -320,7 +320,7 @@
   {
     *t = (struct huft *)NULL;
     *m = 0;
-    return 0;
+    return 2;
   }
 
 DEBG("huft2 ");
@@ -368,6 +368,7 @@
     if ((j = *p++) != 0)
       v[x[j]++] = i;
   } while (++i < n);
+  n = x[g];                   /* set n to length of v */
 
 DEBG("h6 ");
 
@@ -404,12 +405,13 @@
 DEBG1("2 ");
           f -= a + 1;           /* deduct codes from patterns left */
           xp = c + k;
-          while (++j < z)       /* try smaller tables up to z bits */
-          {
-            if ((f <<= 1) <= *++xp)
-              break;            /* enough codes to use up j bits */
-            f -= *xp;           /* else deduct codes from patterns */
-          }
+          if (j < z)
+            while (++j < z)       /* try smaller tables up to z bits */
+            {
+              if ((f <<= 1) <= *++xp)
+                break;            /* enough codes to use up j bits */
+              f -= *xp;           /* else deduct codes from patterns */
+            }
         }
 DEBG1("3 ");
         z = 1 << j;             /* table entries for j-bit table */
diff -urN linux/lib/rbtree.c linux/lib/rbtree.c
--- linux/lib/rbtree.c  2004/11/19 00:28:52     1.1.2.2
+++ linux/lib/rbtree.c  2005/09/23 20:41:28     1.1.2.3
@@ -332,6 +332,7 @@
                node = node->rb_right;
                while (node->rb_left)
                        node = node->rb_left;
+               return node;
        }
 
        /* No right-hand children.  Everything down and left is
@@ -355,6 +356,7 @@
                node = node->rb_left;
                while (node->rb_right)
                        node = node->rb_right;   
+               return node;
        }
 
        /* No left-hand children. Go up till we find an ancestor which
diff -urN linux/net/ipv4/inetpeer.c linux/net/ipv4/inetpeer.c
--- linux/net/ipv4/inetpeer.c   2001/11/05 20:16:33     1.6
+++ linux/net/ipv4/inetpeer.c   2005/09/23 20:41:28     1.6.2.1
@@ -445,9 +445,12 @@
        /* Trigger the timer after inet_peer_gc_mintime .. inet_peer_gc_maxtime
         * interval depending on the total number of entries (more entries,
         * less interval). */
-       peer_periodic_timer.expires = jiffies
-               + inet_peer_gc_maxtime
-               - (inet_peer_gc_maxtime - inet_peer_gc_mintime) / HZ *
-                       peer_total / inet_peer_threshold * HZ;
+       if (peer_total >= inet_peer_threshold)
+               peer_periodic_timer.expires = jiffies + inet_peer_gc_mintime;
+       else
+               peer_periodic_timer.expires = jiffies
+                       + inet_peer_gc_maxtime
+                       - (inet_peer_gc_maxtime - inet_peer_gc_mintime) / HZ *
+                               peer_total / inet_peer_threshold * HZ;
        add_timer(&peer_periodic_timer);
 }
diff -urN linux/net/ipv4/ipvs/ip_vs_conn.c linux/net/ipv4/ipvs/ip_vs_conn.c
--- linux/net/ipv4/ipvs/ip_vs_conn.c    2004/12/27 04:13:56     1.5.2.3
+++ linux/net/ipv4/ipvs/ip_vs_conn.c    2005/09/23 20:41:28     1.5.2.4
@@ -1248,7 +1248,6 @@
 {
        cp->timeout = 0;
        mod_timer(&cp->timer, jiffies);
-       __ip_vs_conn_put(cp);
 }
 
 /*
@@ -1414,7 +1413,6 @@
        int idx;
        struct ip_vs_conn *cp;
        struct list_head *l,*e;
-       struct ip_vs_conn *ct;
 
        /*
         * Randomly scan 1/32 of the whole table every second
@@ -1448,21 +1446,12 @@
                                continue;
                        }
 
-                       /*
-                        * Drop the entry, and drop its ct if not referenced
-                        */
-                       atomic_inc(&cp->refcnt);
-                       ct_write_unlock(hash);
-
-                       if ((ct = cp->control))
-                               atomic_inc(&ct->refcnt);
                        IP_VS_DBG(4, "del connection\n");
                        ip_vs_conn_expire_now(cp);
-                       if (ct) {
+                       if (cp->control) {
                                IP_VS_DBG(4, "del conn template\n");
-                               ip_vs_conn_expire_now(ct);
+                               ip_vs_conn_expire_now(cp->control);
                        }
-                       ct_write_lock(hash);
                }
                ct_write_unlock(hash);
        }
@@ -1477,7 +1466,6 @@
        int idx;
        struct ip_vs_conn *cp;
        struct list_head *l,*e;
-       struct ip_vs_conn *ct;
 
   flush_again:
        for (idx=0; idx<IP_VS_CONN_TAB_SIZE; idx++) {
@@ -1489,18 +1477,13 @@
                l = &ip_vs_conn_tab[idx];
                for (e=l->next; e!=l; e=e->next) {
                        cp = list_entry(e, struct ip_vs_conn, c_list);
-                       atomic_inc(&cp->refcnt);
-                       ct_write_unlock(idx);
 
-                       if ((ct = cp->control))
-                               atomic_inc(&ct->refcnt);
                        IP_VS_DBG(4, "del connection\n");
                        ip_vs_conn_expire_now(cp);
-                       if (ct) {
+                       if (cp->control) {
                                IP_VS_DBG(4, "del conn template\n");
-                               ip_vs_conn_expire_now(ct);
+                               ip_vs_conn_expire_now(cp->control);
                        }
-                       ct_write_lock(idx);
                }
                ct_write_unlock_bh(idx);
        }
diff -urN linux/net/ipv4/netfilter/ip_nat_proto_icmp.c 
linux/net/ipv4/netfilter/ip_nat_proto_icmp.c
--- linux/net/ipv4/netfilter/ip_nat_proto_icmp.c        2000/03/23 02:26:02     
1.1
+++ linux/net/ipv4/netfilter/ip_nat_proto_icmp.c        2005/09/23 20:41:28     
1.1.4.1
@@ -26,16 +26,17 @@
                  const struct ip_conntrack *conntrack)
 {
        static u_int16_t id = 0;
-       unsigned int range_size
-               = (unsigned int)range->max.icmp.id - range->min.icmp.id + 1;
+       unsigned int range_size;
        unsigned int i;
 
+       range_size = ntohs(range->max.icmp.id) - ntohs(range->min.icmp.id) + 1;
        /* If no range specified... */
        if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED))
                range_size = 0xFFFF;
 
        for (i = 0; i < range_size; i++, id++) {
-               tuple->src.u.icmp.id = range->min.icmp.id + (id % range_size);
+               tuple->src.u.icmp.id = htons(ntohs(range->min.icmp.id) +
+                                            (id % range_size));
                if (!ip_nat_used_tuple(tuple, conntrack))
                        return 1;
        }
diff -urN linux/net/ipv4/netfilter/ip_nat_proto_tcp.c 
linux/net/ipv4/netfilter/ip_nat_proto_tcp.c
--- linux/net/ipv4/netfilter/ip_nat_proto_tcp.c 2002/09/11 12:45:44     1.2.2.1
+++ linux/net/ipv4/netfilter/ip_nat_proto_tcp.c 2005/09/23 20:41:28     1.2.2.2
@@ -31,7 +31,8 @@
                 enum ip_nat_manip_type maniptype,
                 const struct ip_conntrack *conntrack)
 {
-       static u_int16_t port = 0, *portptr;
+       static u_int16_t port = 0;
+       u_int16_t *portptr;
        unsigned int range_size, min, i;
 
        if (maniptype == IP_NAT_MANIP_SRC)
diff -urN linux/net/ipv4/netfilter/ip_nat_proto_udp.c 
linux/net/ipv4/netfilter/ip_nat_proto_udp.c
--- linux/net/ipv4/netfilter/ip_nat_proto_udp.c 2000/08/08 18:28:31     1.2
+++ linux/net/ipv4/netfilter/ip_nat_proto_udp.c 2005/09/23 20:41:28     1.2.4.1
@@ -32,7 +32,8 @@
                 enum ip_nat_manip_type maniptype,
                 const struct ip_conntrack *conntrack)
 {
-       static u_int16_t port = 0, *portptr;
+       static u_int16_t port = 0;
+       u_int16_t *portptr;
        unsigned int range_size, min, i;
 
        if (maniptype == IP_NAT_MANIP_SRC)
diff -urN linux/net/ipv4/netfilter/ip_nat_rule.c 
linux/net/ipv4/netfilter/ip_nat_rule.c
--- linux/net/ipv4/netfilter/ip_nat_rule.c      2005/01/20 02:19:25     1.4.2.7
+++ linux/net/ipv4/netfilter/ip_nat_rule.c      2005/09/23 20:41:28     1.4.2.8
@@ -241,6 +241,27 @@
        return ip_nat_setup_info(conntrack, &mr, hooknum);
 }
 
+unsigned int
+alloc_null_binding_confirmed(struct ip_conntrack *conntrack,
+                             struct ip_nat_info *info,
+                             unsigned int hooknum)
+{
+       u_int32_t ip
+               = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC
+                  ? conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip
+                  : conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip);
+       u_int16_t all
+               = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC
+                  ? conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.all
+                  : conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.src.u.all);
+       struct ip_nat_multi_range mr
+               = { 1, { { IP_NAT_RANGE_MAP_IPS, ip, ip, { all }, { all } } } };
+
+       DEBUGP("Allocating NULL binding for confirmed %p (%u.%u.%u.%u)\n",
+              conntrack, NIPQUAD(ip));
+       return ip_nat_setup_info(conntrack, &mr, hooknum);
+}
+
 int ip_nat_rule_find(struct sk_buff **pskb,
                     unsigned int hooknum,
                     const struct net_device *in,
diff -urN linux/net/ipv4/netfilter/ip_nat_standalone.c 
linux/net/ipv4/netfilter/ip_nat_standalone.c
--- linux/net/ipv4/netfilter/ip_nat_standalone.c        2005/03/18 12:13:32     
1.12.2.11
+++ linux/net/ipv4/netfilter/ip_nat_standalone.c        2005/09/23 20:41:28     
1.12.2.12
@@ -123,8 +123,12 @@
                                ret = call_expect(master_ct(ct), pskb, 
                                                  hooknum, ct, info);
                        } else {
-                               /* LOCAL_IN hook doesn't have a chain!  */
-                               if (hooknum == NF_IP_LOCAL_IN)
+                               if (unlikely(is_confirmed(ct)))
+                                       /* NAT module was loaded late */
+                                       ret = alloc_null_binding_confirmed(ct, 
info,
+                                                                          
hooknum);
+                               else if (hooknum == NF_IP_LOCAL_IN)
+                                       /* LOCAL_IN hook doesn't have a chain */
                                        ret = alloc_null_binding(ct, info,
                                                                 hooknum);
                                else
diff -urN linux/net/ipv4/netfilter/ip_queue.c 
linux/net/ipv4/netfilter/ip_queue.c
--- linux/net/ipv4/netfilter/ip_queue.c 2003/12/15 18:19:54     1.15.2.5
+++ linux/net/ipv4/netfilter/ip_queue.c 2005/09/23 20:41:28     1.15.2.6
@@ -62,7 +62,9 @@
 static void
 ipq_issue_verdict(struct ipq_queue_entry *entry, int verdict)
 {
+       local_bh_disable();
        nf_reinject(entry->skb, entry->info, verdict);
+       local_bh_enable();
        kfree(entry);
 }
 
diff -urN linux/net/ipv4/netfilter/ipt_unclean.c 
linux/net/ipv4/netfilter/ipt_unclean.c
--- linux/net/ipv4/netfilter/Attic/ipt_unclean.c        2004/08/14 18:39:05     
1.6.2.5
+++ linux/net/ipv4/netfilter/Attic/ipt_unclean.c        2005/09/23 20:41:28     
1.6.2.6
@@ -264,6 +264,7 @@
 {
        [TH_SYN]                        = 1,
        [TH_SYN|TH_ACK]                 = 1,
+       [TH_SYN|TH_ACK|TH_PUSH]         = 1,
        [TH_RST]                        = 1,
        [TH_RST|TH_ACK]                 = 1,
        [TH_RST|TH_ACK|TH_PUSH]         = 1,
diff -urN linux/net/ipv6/addrconf.c linux/net/ipv6/addrconf.c
--- linux/net/ipv6/addrconf.c   2004/11/19 00:29:04     1.29.2.8
+++ linux/net/ipv6/addrconf.c   2005/09/23 20:41:29     1.29.2.9
@@ -883,7 +883,7 @@
        if (dev->type == ARPHRD_SIT && (dev->flags&IFF_POINTOPOINT))
                rtmsg.rtmsg_flags |= RTF_NONEXTHOP;
 
-       ip6_route_add(&rtmsg, NULL);
+       ip6_route_add(&rtmsg, NULL, NULL);
 }
 
 /* Create "default" multicast route to the interface */
@@ -900,7 +900,7 @@
        rtmsg.rtmsg_ifindex = dev->ifindex;
        rtmsg.rtmsg_flags = RTF_UP;
        rtmsg.rtmsg_type = RTMSG_NEWROUTE;
-       ip6_route_add(&rtmsg, NULL);
+       ip6_route_add(&rtmsg, NULL, NULL);
 }
 
 static void sit_route_add(struct net_device *dev)
@@ -917,7 +917,7 @@
        rtmsg.rtmsg_flags       = RTF_UP|RTF_NONEXTHOP;
        rtmsg.rtmsg_ifindex     = dev->ifindex;
 
-       ip6_route_add(&rtmsg, NULL);
+       ip6_route_add(&rtmsg, NULL, NULL);
 }
 
 static void addrconf_add_lroute(struct net_device *dev)
@@ -1009,7 +1009,7 @@
        if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) {
                if (rt->rt6i_flags&RTF_EXPIRES) {
                        if (pinfo->onlink == 0 || valid_lft == 0) {
-                               ip6_del_rt(rt, NULL);
+                               ip6_del_rt(rt, NULL, NULL);
                                rt = NULL;
                        } else {
                                rt->rt6i_expires = rt_expires;
@@ -1592,7 +1592,7 @@
 
                rtmsg.rtmsg_ifindex = ifp->idev->dev->ifindex;
 
-               ip6_route_add(&rtmsg, NULL);
+               ip6_route_add(&rtmsg, NULL, NULL);
        }
 
 out:
diff -urN linux/net/ipv6/ip6_fib.c linux/net/ipv6/ip6_fib.c
--- linux/net/ipv6/ip6_fib.c    2004/11/19 00:29:04     1.17.2.5
+++ linux/net/ipv6/ip6_fib.c    2005/09/23 20:41:29     1.17.2.6
@@ -424,7 +424,7 @@
  */
 
 static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
-    struct nlmsghdr *nlh)
+               struct nlmsghdr *nlh,  struct netlink_skb_parms *req)
 {
        struct rt6_info *iter = NULL;
        struct rt6_info **ins;
@@ -482,7 +482,7 @@
        *ins = rt;
        rt->rt6i_node = fn;
        atomic_inc(&rt->rt6i_ref);
-       inet6_rt_notify(RTM_NEWROUTE, rt, nlh);
+       inet6_rt_notify(RTM_NEWROUTE, rt, nlh, req);
        rt6_stats.fib_rt_entries++;
 
        if ((fn->fn_flags & RTN_RTINFO) == 0) {
@@ -506,7 +506,8 @@
  *     with source addr info in sub-trees
  */
 
-int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nlmsghdr *nlh)
+int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nlmsghdr *nlh,
+               struct netlink_skb_parms *req)
 {
        struct fib6_node *fn;
        int err = -ENOMEM;
@@ -579,7 +580,7 @@
        }
 #endif
 
-       err = fib6_add_rt2node(fn, rt, nlh);
+       err = fib6_add_rt2node(fn, rt, nlh, req);
 
        if (err == 0) {
                fib6_start_gc(rt);
@@ -888,7 +889,7 @@
 }
 
 static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp,
-    struct nlmsghdr *nlh)
+    struct nlmsghdr *nlh, struct netlink_skb_parms *req)
 {
        struct fib6_walker_t *w;
        struct rt6_info *rt = *rtp;
@@ -943,11 +944,11 @@
                if (atomic_read(&rt->rt6i_ref) != 1) BUG();
        }
 
-       inet6_rt_notify(RTM_DELROUTE, rt, nlh);
+       inet6_rt_notify(RTM_DELROUTE, rt, nlh, req);
        rt6_release(rt);
 }
 
-int fib6_del(struct rt6_info *rt, struct nlmsghdr *nlh)
+int fib6_del(struct rt6_info *rt, struct nlmsghdr *nlh, struct 
netlink_skb_parms *req)
 {
        struct fib6_node *fn = rt->rt6i_node;
        struct rt6_info **rtp;
@@ -972,7 +973,7 @@
 
        for (rtp = &fn->leaf; *rtp; rtp = &(*rtp)->u.next) {
                if (*rtp == rt) {
-                       fib6_del_route(fn, rtp, nlh);
+                       fib6_del_route(fn, rtp, nlh, req);
                        return 0;
                }
        }
@@ -1101,7 +1102,7 @@
                res = c->func(rt, c->arg);
                if (res < 0) {
                        w->leaf = rt;
-                       res = fib6_del(rt, NULL);
+                       res = fib6_del(rt, NULL, NULL);
                        if (res) {
 #if RT6_DEBUG >= 2
                                printk(KERN_DEBUG "fib6_clean_node: del failed: 
rt=%p@%p err=%d\n", rt, rt->rt6i_node, res);
diff -urN linux/net/ipv6/mcast.c linux/net/ipv6/mcast.c
--- linux/net/ipv6/mcast.c      2004/12/27 04:13:57     1.22.2.12
+++ linux/net/ipv6/mcast.c      2005/09/23 20:41:29     1.22.2.13
@@ -1243,15 +1243,6 @@
                return 0;
 
        skb_reserve(skb, (dev->hard_header_len + 15) & ~15);
-       if (dev->hard_header) {
-               unsigned char ha[MAX_ADDR_LEN];
-
-               ndisc_mc_map(&mld2_all_mcr, ha, dev, 1);
-               if (dev->hard_header(skb, dev, ETH_P_IPV6,ha,NULL,size) < 0) {
-                       kfree_skb(skb);
-                       return 0;
-               }
-       }
 
        if (ipv6_get_lladdr(dev, &addr_buf)) {
                /* <draft-ietf-magma-mld-source-02.txt>:
@@ -1275,6 +1266,30 @@
        return skb;
 }
 
+static inline int mld_dev_queue_xmit2(struct sk_buff *skb)
+{
+       struct net_device *dev = skb->dev;
+
+       if (dev->hard_header) {
+               unsigned char ha[MAX_ADDR_LEN];
+               int err;
+
+               ndisc_mc_map(&skb->nh.ipv6h->daddr, ha, dev, 1);
+               err = dev->hard_header(skb, dev, ETH_P_IPV6, ha, NULL, 
skb->len);
+               if (err < 0) {
+                       kfree_skb(skb);
+                       return err;
+               }
+       }
+       return dev_queue_xmit(skb);
+}
+
+static inline int mld_dev_queue_xmit(struct sk_buff *skb)
+{
+       return NF_HOOK(PF_INET6, NF_IP6_POST_ROUTING, skb, NULL, skb->dev,
+                      mld_dev_queue_xmit2);
+}
+
 static void mld_sendpack(struct sk_buff *skb)
 {
        struct ipv6hdr *pip6 = skb->nh.ipv6h;
@@ -1289,7 +1304,7 @@
        pmr->csum = csum_ipv6_magic(&pip6->saddr, &pip6->daddr, mldlen,
                IPPROTO_ICMPV6, csum_partial(skb->h.raw, mldlen, 0));
        err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, skb->dev,
-                     dev_queue_xmit);
+                     mld_dev_queue_xmit);
        if (!err)
                ICMP6_INC_STATS(Icmp6OutMsgs);
 }
@@ -1585,12 +1600,6 @@
                return;
 
        skb_reserve(skb, (dev->hard_header_len + 15) & ~15);
-       if (dev->hard_header) {
-               unsigned char ha[MAX_ADDR_LEN];
-               ndisc_mc_map(snd_addr, ha, dev, 1);
-               if (dev->hard_header(skb, dev, ETH_P_IPV6, ha, NULL, full_len) 
< 0)
-                       goto out;
-       }
 
        if (ipv6_get_lladdr(dev, &addr_buf)) {
                /* <draft-ietf-magma-mld-source-02.txt>:
@@ -1616,7 +1625,7 @@
                                           csum_partial((__u8 *) hdr, len, 0));
 
        err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, skb->dev,
-                     dev_queue_xmit);
+                     mld_dev_queue_xmit);
        if (!err) {
                if (type == ICMPV6_MGM_REDUCTION)
                        ICMP6_INC_STATS(Icmp6OutGroupMembReductions);
@@ -1626,9 +1635,6 @@
        }
 
        return;
-
-out:
-       kfree_skb(skb);
 }
 
 static int ip6_mc_del1_src(struct ifmcaddr6 *pmc, int sfmode,
diff -urN linux/net/ipv6/ndisc.c linux/net/ipv6/ndisc.c
--- linux/net/ipv6/ndisc.c      2004/11/19 00:29:04     1.22.2.10
+++ linux/net/ipv6/ndisc.c      2005/09/23 20:41:29     1.22.2.11
@@ -876,7 +876,7 @@
                                        /* It is safe only because
                                           we aer in BH */
                                        dst_release(&rt->u.dst);
-                                       ip6_del_rt(rt, NULL);
+                                       ip6_del_rt(rt, NULL, NULL);
                                }
                        }
                } else {
@@ -962,7 +962,7 @@
        rt = rt6_get_dflt_router(&skb->nh.ipv6h->saddr, skb->dev);
 
        if (rt && lifetime == 0) {
-               ip6_del_rt(rt, NULL);
+               ip6_del_rt(rt, NULL, NULL);
                rt = NULL;
        }
 
diff -urN linux/net/ipv6/route.c linux/net/ipv6/route.c
--- linux/net/ipv6/route.c      2004/11/19 00:29:04     1.29.2.8
+++ linux/net/ipv6/route.c      2005/09/23 20:41:29     1.29.2.9
@@ -325,12 +325,12 @@
    be destroyed.
  */
 
-static int rt6_ins(struct rt6_info *rt, struct nlmsghdr *nlh)
+static int rt6_ins(struct rt6_info *rt, struct nlmsghdr *nlh, struct 
netlink_skb_parms *req)
 {
        int err;
 
        write_lock_bh(&rt6_lock);
-       err = fib6_add(&ip6_routing_table, rt, nlh);
+       err = fib6_add(&ip6_routing_table, rt, nlh, req);
        write_unlock_bh(&rt6_lock);
 
        return err;
@@ -341,7 +341,7 @@
  */
 
 static struct rt6_info *rt6_cow(struct rt6_info *ort, struct in6_addr *daddr,
-                               struct in6_addr *saddr)
+                               struct in6_addr *saddr, struct 
netlink_skb_parms *req)
 {
        int err;
        struct rt6_info *rt;
@@ -373,7 +373,7 @@
 
                dst_hold(&rt->u.dst);
 
-               err = rt6_ins(rt, NULL);
+               err = rt6_ins(rt, NULL, req);
                if (err == 0)
                        return rt;
 
@@ -479,7 +479,8 @@
                        read_unlock_bh(&rt6_lock);
 
                        rt = rt6_cow(rt, &skb->nh.ipv6h->daddr,
-                                    &skb->nh.ipv6h->saddr);
+                                    &skb->nh.ipv6h->saddr,
+                                    &NETLINK_CB(skb));
                        
                        if (rt->u.dst.error != -EEXIST || --attempts <= 0)
                                goto out2;
@@ -558,7 +559,7 @@
                        read_unlock_bh(&rt6_lock);
 
                        rt = rt6_cow(rt, fl->nl_u.ip6_u.daddr,
-                                    fl->nl_u.ip6_u.saddr);
+                                    fl->nl_u.ip6_u.saddr, NULL);
                        
                        if (rt->u.dst.error != -EEXIST || --attempts <= 0)
                                goto out2;
@@ -619,7 +620,7 @@
 
        if (rt) {
                if (rt->rt6i_flags & RTF_CACHE)
-                       ip6_del_rt(rt, NULL);
+                       ip6_del_rt(rt, NULL, NULL);
                else
                        dst_release(dst);
        }
@@ -712,7 +713,7 @@
  *
  */
 
-int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh)
+int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, struct 
netlink_skb_parms *req)
 {
        int err;
        struct rtmsg *r;
@@ -865,7 +866,7 @@
        if (rt->u.dst.advmss > 65535-20)
                rt->u.dst.advmss = 65535;
        rt->u.dst.dev = dev;
-       return rt6_ins(rt, nlh);
+       return rt6_ins(rt, nlh, req);
 
 out:
        if (dev)
@@ -874,7 +875,7 @@
        return err;
 }
 
-int ip6_del_rt(struct rt6_info *rt, struct nlmsghdr *nlh)
+int ip6_del_rt(struct rt6_info *rt, struct nlmsghdr *nlh, struct 
netlink_skb_parms *req)
 {
        int err;
 
@@ -886,13 +887,13 @@
 
        dst_release(&rt->u.dst);
 
-       err = fib6_del(rt, nlh);
+       err = fib6_del(rt, nlh, req);
        write_unlock_bh(&rt6_lock);
 
        return err;
 }
 
-int ip6_route_del(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh)
+int ip6_route_del(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, struct 
netlink_skb_parms *req)
 {
        struct fib6_node *fn;
        struct rt6_info *rt;
@@ -919,7 +920,7 @@
                        dst_hold(&rt->u.dst);
                        read_unlock_bh(&rt6_lock);
 
-                       return ip6_del_rt(rt, nlh);
+                       return ip6_del_rt(rt, nlh, req);
                }
        }
        read_unlock_bh(&rt6_lock);
@@ -1021,11 +1022,11 @@
                rt->u.dst.advmss = 65535;
        nrt->rt6i_hoplimit = ipv6_get_hoplimit(neigh->dev);
 
-       if (rt6_ins(nrt, NULL))
+       if (rt6_ins(nrt, NULL, NULL))
                goto out;
 
        if (rt->rt6i_flags&RTF_CACHE) {
-               ip6_del_rt(rt, NULL);
+               ip6_del_rt(rt, NULL, NULL);
                return;
        }
 
@@ -1087,7 +1088,7 @@
           2. It is gatewayed route or NONEXTHOP route. Action: clone it.
         */
        if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) {
-               nrt = rt6_cow(rt, daddr, saddr);
+               nrt = rt6_cow(rt, daddr, saddr, NULL);
                if (!nrt->u.dst.error) {
                        nrt->u.dst.pmtu = pmtu;
                        /* According to RFC 1981, detecting PMTU increase 
shouldn't be
@@ -1111,7 +1112,7 @@
                dst_set_expires(&nrt->u.dst, ip6_rt_mtu_expires);
                nrt->rt6i_flags |= RTF_DYNAMIC|RTF_CACHE|RTF_EXPIRES;
                nrt->u.dst.pmtu = pmtu;
-               rt6_ins(nrt, NULL);
+               rt6_ins(nrt, NULL, NULL);
        }
 
 out:
@@ -1184,7 +1185,7 @@
 
        rtmsg.rtmsg_ifindex = dev->ifindex;
 
-       ip6_route_add(&rtmsg, NULL);
+       ip6_route_add(&rtmsg, NULL, NULL);
        return rt6_get_dflt_router(gwaddr, dev);
 }
 
@@ -1210,7 +1211,7 @@
 
                        read_unlock_bh(&rt6_lock);
 
-                       ip6_del_rt(rt, NULL);
+                       ip6_del_rt(rt, NULL, NULL);
 
                        goto restart;
                }
@@ -1236,10 +1237,10 @@
                rtnl_lock();
                switch (cmd) {
                case SIOCADDRT:
-                       err = ip6_route_add(&rtmsg, NULL);
+                       err = ip6_route_add(&rtmsg, NULL, NULL);
                        break;
                case SIOCDELRT:
-                       err = ip6_route_del(&rtmsg, NULL);
+                       err = ip6_route_del(&rtmsg, NULL, NULL);
                        break;
                default:
                        err = -EINVAL;
@@ -1296,7 +1297,7 @@
 
        ipv6_addr_copy(&rt->rt6i_dst.addr, addr);
        rt->rt6i_dst.plen = 128;
-       rt6_ins(rt, NULL);
+       rt6_ins(rt, NULL, NULL);
 
        return 0;
 }
@@ -1313,7 +1314,7 @@
        rt = rt6_lookup(addr, NULL, loopback_dev.ifindex, 1);
        if (rt) {
                if (rt->rt6i_dst.plen == 128)
-                       err = ip6_del_rt(rt, NULL);
+                       err = ip6_del_rt(rt, NULL, NULL);
                else
                        dst_release(&rt->u.dst);
        }
@@ -1429,7 +1430,7 @@
 
        nrt->rt6i_flags |= RTF_CACHE;
        dst_hold(&nrt->u.dst);
-       err = rt6_ins(nrt, NULL);
+       err = rt6_ins(nrt, NULL, NULL);
        if (err)
                nrt->u.dst.error = err;
        return nrt;
@@ -1556,7 +1557,7 @@
 
        if (inet6_rtm_to_rtmsg(r, arg, &rtmsg))
                return -EINVAL;
-       return ip6_route_del(&rtmsg, nlh);
+       return ip6_route_del(&rtmsg, nlh, &NETLINK_CB(skb));
 }
 
 int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
@@ -1566,7 +1567,7 @@
 
        if (inet6_rtm_to_rtmsg(r, arg, &rtmsg))
                return -EINVAL;
-       return ip6_route_add(&rtmsg, nlh);
+       return ip6_route_add(&rtmsg, nlh, &NETLINK_CB(skb));
 }
 
 struct rt6_rtnl_dump_arg
@@ -1576,11 +1577,8 @@
 };
 
 static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt,
-                        struct in6_addr *dst,
-                        struct in6_addr *src,
-                        int iif,
-                        int type, u32 pid, u32 seq,
-                        struct nlmsghdr *in_nlh, int prefix)
+                        struct in6_addr *dst, struct in6_addr *src,
+                        int iif, int type, u32 pid, u32 seq, int prefix)
 {
        struct rtmsg *rtm;
        struct nlmsghdr  *nlh;
@@ -1593,9 +1591,6 @@
                        return 1;
                }
        }
-       if (!pid && in_nlh) {
-               pid = in_nlh->nlmsg_pid;
-       }
 
        nlh = NLMSG_PUT(skb, pid, seq, type, sizeof(*rtm));
        rtm = NLMSG_DATA(nlh);
@@ -1683,7 +1678,7 @@
 
        return rt6_fill_node(arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE,
                     NETLINK_CB(arg->cb->skb).pid, arg->cb->nlh->nlmsg_seq,
-                    NULL, prefix);
+                    prefix);
 }
 
 static int fib6_dump_node(struct fib6_walker_t *w)
@@ -1834,7 +1829,7 @@
                            fl.nl_u.ip6_u.saddr,
                            iif,
                            RTM_NEWROUTE, NETLINK_CB(in_skb).pid,
-                           nlh->nlmsg_seq, nlh, 0);
+                           nlh->nlmsg_seq, 0);
        if (err < 0) {
                err = -EMSGSIZE;
                goto out_free;
@@ -1850,17 +1845,25 @@
        goto out;       
 }
 
-void inet6_rt_notify(int event, struct rt6_info *rt, struct nlmsghdr *nlh)
+void inet6_rt_notify(int event, struct rt6_info *rt, struct nlmsghdr *nlh,
+                     struct netlink_skb_parms *req)
 {
        struct sk_buff *skb;
        int size = NLMSG_SPACE(sizeof(struct rtmsg)+256);
+       u32 pid = current->pid;
+       u32 seq = 0;
+
+       if (req)
+               pid = req->pid;
+       if (nlh)
+               seq = nlh->nlmsg_seq;
 
        skb = alloc_skb(size, gfp_any());
        if (!skb) {
                netlink_set_err(rtnl, 0, RTMGRP_IPV6_ROUTE, ENOBUFS);
                return;
        }
-       if (rt6_fill_node(skb, rt, NULL, NULL, 0, event, 0, 0, nlh, 0) < 0) {
+       if (rt6_fill_node(skb, rt, NULL, NULL, 0, event, pid, seq, 0) < 0) {
                kfree_skb(skb);
                netlink_set_err(rtnl, 0, RTMGRP_IPV6_ROUTE, EINVAL);
                return;
diff -urN linux/net/ipv6/netfilter/ip6_queue.c 
linux/net/ipv6/netfilter/ip6_queue.c
--- linux/net/ipv6/netfilter/ip6_queue.c        2003/12/15 18:19:54     1.1.2.6
+++ linux/net/ipv6/netfilter/ip6_queue.c        2005/09/23 20:41:29     1.1.2.7
@@ -68,7 +68,9 @@
 static void
 ipq_issue_verdict(struct ipq_queue_entry *entry, int verdict)
 {
+       local_bh_disable();
        nf_reinject(entry->skb, entry->info, verdict);
+       local_bh_enable();
        kfree(entry);
 }
 
diff -urN linux/net/ipv6/netfilter/ip6t_LOG.c 
linux/net/ipv6/netfilter/ip6t_LOG.c
--- linux/net/ipv6/netfilter/ip6t_LOG.c 2005/01/20 02:19:25     1.1.2.4
+++ linux/net/ipv6/netfilter/ip6t_LOG.c 2005/09/23 20:41:29     1.1.2.5
@@ -363,7 +363,6 @@
                const void *targinfo,
                void *userinfo)
 {
-       struct ipv6hdr *ipv6h = (*pskb)->nh.ipv6h;
        const struct ip6t_log_info *loginfo = targinfo;
        char level_string[4] = "< >";
 
@@ -375,41 +374,32 @@
                in ? in->name : "",
                out ? out->name : "");
        if (in && !out) {
+               unsigned int len;
                /* MAC logging for input chain only. */
                printk("MAC=");
-               if ((*pskb)->dev && (*pskb)->dev->hard_header_len && 
(*pskb)->mac.raw != (void*)ipv6h) {
-                       if ((*pskb)->dev->type != ARPHRD_SIT){
-                         int i;
-                         unsigned char *p = (*pskb)->mac.raw;
-                         for (i = 0; i < (*pskb)->dev->hard_header_len; 
i++,p++)
-                               printk("%02x%c", *p,
-                                       i==(*pskb)->dev->hard_header_len - 1
-                                       ? ' ':':');
-                       } else {
-                         int i;
-                         unsigned char *p = (*pskb)->mac.raw;
-                         if ( p - (ETH_ALEN*2+2) > (*pskb)->head ){
-                           p -= (ETH_ALEN+2);
-                           for (i = 0; i < (ETH_ALEN); i++,p++)
-                               printk("%02x%s", *p,
-                                       i == ETH_ALEN-1 ? "->" : ":");
-                           p -= (ETH_ALEN*2);
-                           for (i = 0; i < (ETH_ALEN); i++,p++)
-                               printk("%02x%c", *p,
-                                       i == ETH_ALEN-1 ? ' ' : ':');
-                         }
-                         
-                         if (((*pskb)->dev->addr_len == 4) &&
-                             (*pskb)->dev->hard_header_len > 20){
-                           printk("TUNNEL=");
-                           p = (*pskb)->mac.raw + 12;
-                           for (i = 0; i < 4; i++,p++)
-                               printk("%3d%s", *p,
-                                       i == 3 ? "->" : ".");
-                           for (i = 0; i < 4; i++,p++)
-                               printk("%3d%c", *p,
-                                       i == 3 ? ' ' : '.');
-                         }
+               if ((*pskb)->dev && (len = (*pskb)->dev->hard_header_len) &&
+                   (*pskb)->mac.raw != (*pskb)->nh.raw) {
+                       unsigned char *p = (*pskb)->mac.raw;
+                       int i;
+
+                       if ((*pskb)->dev->type == ARPHRD_SIT &&
+                           (p -= ETH_HLEN) < (*pskb)->head)
+                               p = NULL;
+
+                       if (p != NULL) {
+                               for (i = 0; i < len; i++)
+                                       printk("%02x%s", p[i],
+                                              i == len - 1 ? "" : ":");
+                       }
+                       printk(" ");
+
+                       if ((*pskb)->dev->type == ARPHRD_SIT) {
+                               struct iphdr *iph;
+                               
+                               iph = (struct iphdr *)(*pskb)->mac.raw;
+                               printk("TUNNEL=%u.%u.%u.%u->%u.%u.%u.%u ",
+                                      NIPQUAD(iph->saddr),
+                                      NIPQUAD(iph->daddr));
                        }
                } else
                        printk(" ");
diff -urN linux/net/netlink/af_netlink.c linux/net/netlink/af_netlink.c
--- linux/net/netlink/af_netlink.c      2005/05/05 13:43:42     1.19.2.10
+++ linux/net/netlink/af_netlink.c      2005/09/23 20:41:30     1.19.2.11
@@ -330,9 +330,9 @@
        u32 pid = nlk_sk(sk)->pid;
 
        netlink_table_grab();
-       hash->entries--;
        for (skp = nl_pid_hashfn(hash, pid); *skp; skp = &((*skp)->next)) {
                if (*skp == sk) {
+                       hash->entries--;
                        *skp = sk->next;
                        __sock_put(sk);
                        break;
@@ -450,7 +450,12 @@
        err = netlink_insert(sk, pid);
        if (err == -EADDRINUSE)
                goto retry;
-       return 0;
+
+       /* If 2 threads race to autobind, that is fine.  */
+       if (err == -EBUSY)
+               err = 0;
+
+       return err;
 }
 
 static inline int netlink_capable(struct socket *sock, unsigned int flag) 

<Prev in Thread] Current Thread [Next in Thread>