]> git.neil.brown.name Git - history.git/commitdiff
Import 2.3.17pre1 2.3.17pre1
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:27:13 +0000 (15:27 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:27:13 +0000 (15:27 -0500)
201 files changed:
Documentation/Configure.help
MAINTAINERS
Makefile
arch/alpha/kernel/Makefile
arch/alpha/kernel/core_apecs.c
arch/alpha/kernel/core_cia.c
arch/alpha/kernel/core_lca.c
arch/alpha/kernel/core_mcpcia.c
arch/alpha/kernel/core_pyxis.c
arch/alpha/kernel/core_t2.c
arch/alpha/kernel/core_tsunami.c
arch/alpha/kernel/pci.c
arch/alpha/kernel/pci_impl.h
arch/alpha/kernel/pci_setup.c [deleted file]
arch/alpha/kernel/pci_syscall.c [deleted file]
arch/alpha/kernel/sys_rawhide.c
arch/arm/kernel/bios32.c
arch/arm/mm/proc-sa110.S
arch/i386/config.in
arch/i386/defconfig
arch/i386/kernel/apm.c
arch/i386/kernel/setup.c
arch/i386/kernel/traps.c
arch/mips/kernel/head.S
arch/ppc/kernel/gemini_prom.S
arch/ppc/kernel/gemini_setup.c
arch/sh/kernel/irq_onchip.c
arch/sh/kernel/process.c
arch/sh/kernel/ptrace.c
arch/sh/kernel/time.c
arch/sh/kernel/traps.c
arch/sh/mm/fault.c
arch/sh/vmlinux.lds.S
arch/sparc/ap1000/msc.c
arch/sparc/ap1000/sync.c
arch/sparc/kernel/smp.c
arch/sparc/kernel/sun4d_smp.c
arch/sparc/kernel/sun4m_smp.c
arch/sparc64/kernel/devices.c
arch/sparc64/kernel/pci.c
arch/sparc64/kernel/smp.c
drivers/Makefile
drivers/block/floppy.c
drivers/block/hpt366.c
drivers/block/ide-cd.c
drivers/block/loop.c
drivers/cdrom/cdrom.c
drivers/char/Config.in
drivers/char/applicom.c
drivers/char/istallion.c
drivers/char/n_r3964.c
drivers/char/serial.c
drivers/char/stallion.c
drivers/i2o/i2o_pci.c
drivers/i2o/i2o_scsi.c
drivers/isdn/eicon/eicon_mod.c
drivers/isdn/hisax/amd7930.c
drivers/isdn/hisax/asuscom.c
drivers/isdn/hisax/avm_a1.c
drivers/isdn/hisax/avm_a1p.c
drivers/isdn/hisax/avm_pci.c
drivers/isdn/hisax/bkm_a4t.c
drivers/isdn/hisax/bkm_a8.c
drivers/isdn/hisax/config.c
drivers/isdn/hisax/diva.c
drivers/isdn/hisax/gazel.c
drivers/isdn/hisax/hfc_2bds0.c
drivers/isdn/hisax/hfc_2bs0.c
drivers/isdn/hisax/hfc_pci.c
drivers/isdn/hisax/hfcscard.c
drivers/isdn/hisax/hisax.h
drivers/isdn/hisax/isurf.c
drivers/isdn/hisax/ix1_micro.c
drivers/isdn/hisax/mic.c
drivers/isdn/hisax/netjet.c
drivers/isdn/hisax/niccy.c
drivers/isdn/hisax/s0box.c
drivers/isdn/hisax/saphir.c
drivers/isdn/hisax/sedlbauer.c
drivers/isdn/hisax/sportster.c
drivers/isdn/hisax/teleint.c
drivers/isdn/hisax/teles0.c
drivers/isdn/hisax/teles3.c
drivers/isdn/hisax/telespci.c
drivers/net/defxx.c
drivers/net/hamradio/yam.c
drivers/net/ppp_async.c
drivers/net/ppp_generic.c
drivers/pci/Makefile
drivers/pci/pci.c
drivers/pci/quirks.c
drivers/pci/setup.c [new file with mode: 0644]
drivers/pci/syscall.c [new file with mode: 0644]
drivers/pcmcia/Config.in [new file with mode: 0644]
drivers/pcmcia/Makefile [new file with mode: 0644]
drivers/pcmcia/bulkmem.c [new file with mode: 0644]
drivers/pcmcia/cardbus.c [new file with mode: 0644]
drivers/pcmcia/cb_enabler.c [new file with mode: 0644]
drivers/pcmcia/cirrus.h [new file with mode: 0644]
drivers/pcmcia/cistpl.c [new file with mode: 0644]
drivers/pcmcia/cs.c [new file with mode: 0644]
drivers/pcmcia/cs_internal.h [new file with mode: 0644]
drivers/pcmcia/ds.c [new file with mode: 0644]
drivers/pcmcia/i82365.c [new file with mode: 0644]
drivers/pcmcia/i82365.h [new file with mode: 0644]
drivers/pcmcia/o2micro.h [new file with mode: 0644]
drivers/pcmcia/ricoh.h [new file with mode: 0644]
drivers/pcmcia/rsrc_mgr.c [new file with mode: 0644]
drivers/pcmcia/rsrc_mgr.h [new file with mode: 0644]
drivers/pcmcia/smc34c90.h [new file with mode: 0644]
drivers/pcmcia/tcic.c [new file with mode: 0644]
drivers/pcmcia/tcic.h [new file with mode: 0644]
drivers/pcmcia/ti113x.h [new file with mode: 0644]
drivers/pcmcia/topic.h [new file with mode: 0644]
drivers/pcmcia/vg468.h [new file with mode: 0644]
drivers/pcmcia/yenta.h [new file with mode: 0644]
drivers/scsi/advansys.c
drivers/scsi/i60uscsi.c
drivers/scsi/i60uscsi.h
drivers/scsi/in2000.c
drivers/scsi/inia100.c
drivers/scsi/inia100.h
drivers/scsi/sr.c
drivers/sound/Config.in
drivers/sound/es1370.c
drivers/sound/es1371.c
drivers/sound/esssolo1.c
drivers/sound/sonicvibes.c
drivers/usb/CREDITS
drivers/usb/Config.in
drivers/usb/Makefile
drivers/usb/README.hp_scanner [new file with mode: 0644]
drivers/usb/README.hp_scanner_sane [new file with mode: 0644]
drivers/usb/cpia.c
drivers/usb/cpia.h
drivers/usb/ezusb.c
drivers/usb/hp_scanner.c [new file with mode: 0644]
drivers/usb/inits.h
drivers/usb/mouse.c
drivers/usb/ohci.c
drivers/usb/uhci.c
drivers/usb/usb-core.c
drivers/usb/usb.h
drivers/usb/usb_scsi.c
fs/Config.in
fs/buffer.c
fs/ext2/inode.c
fs/ncpfs/sock.c
fs/nfsd/vfs.c
include/asm-alpha/core_cia.h
include/asm-alpha/core_lca.h
include/asm-alpha/core_mcpcia.h
include/asm-alpha/core_polaris.h
include/asm-alpha/core_pyxis.h
include/asm-alpha/core_tsunami.h
include/asm-alpha/serial.h
include/asm-alpha/smp.h
include/asm-arm/hardirq.h
include/asm-arm/iomd.h
include/asm-i386/bugs.h
include/asm-i386/fixmap.h
include/asm-mips/hardirq.h
include/asm-ppc/gemini_serial.h
include/asm-ppc/pmu.h
include/asm-sh/bugs.h
include/asm-sh/elf.h
include/asm-sparc/ap1000/apreg.h
include/asm-sparc/audioio.h
include/asm-sparc64/audioio.h
include/asm-sparc64/dma.h
include/asm-sparc64/hardirq.h
include/linux/cd1400.h
include/linux/cdk.h
include/linux/comstats.h
include/linux/i2o.h
include/linux/ioport.h
include/linux/istallion.h
include/linux/pagemap.h
include/linux/pci.h
include/linux/serialP.h
include/linux/stallion.h
include/linux/tty.h
include/pcmcia/bulkmem.h [new file with mode: 0644]
include/pcmcia/bus_ops.h [new file with mode: 0644]
include/pcmcia/ciscode.h [new file with mode: 0644]
include/pcmcia/cisreg.h [new file with mode: 0644]
include/pcmcia/cistpl.h [new file with mode: 0644]
include/pcmcia/cs.h [new file with mode: 0644]
include/pcmcia/cs_types.h [new file with mode: 0644]
include/pcmcia/driver_ops.h [new file with mode: 0644]
include/pcmcia/ds.h [new file with mode: 0644]
include/pcmcia/ftl.h [new file with mode: 0644]
include/pcmcia/mem_op.h [new file with mode: 0644]
include/pcmcia/memory.h [new file with mode: 0644]
include/pcmcia/ss.h [new file with mode: 0644]
include/pcmcia/version.h [new file with mode: 0644]
init/main.c
kernel/ksyms.c
mm/filemap.c
net/core/iovec.c
net/khttpd/misc.c

index 5c7ad1ba750057ef411b7d519fc6c1f286ce2ff2..56e67da2e35b01f17fbf146e662143f7f808ff94 100644 (file)
@@ -4835,8 +4835,8 @@ CONFIG_SCSI_AM53C974
 
 AMI MegaRAID support
 CONFIG_SCSI_MEGARAID
-  This driver supports the AMI MegaRAID 428 and 438 (and maybe 466)
-  SCSI host adapters. 
+  This driver supports the AMI MegaRAID 418, 428, 438, 466, 762, 490
+  and 467 SCSI host adapters. 
 
   If you want to compile this driver as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
@@ -6043,6 +6043,25 @@ CONFIG_YELLOWFIN
   say M here and read Documentation/modules.txt. This is recommended.
   The module will be called yellowfin.o.
 
+General Instruments Surfboard 1000
+CONFIG_NET_SB1000
+  This is a driver for the General Instrument SURFboard 1000 internal cable
+  modem.  This is an ISA card which is used by a number of cable TV companies
+  to provide cable modem access.  It's a one-way downstream-only cable modem,
+  meaning that your upstream net link is provided by your regular phone modem.
+
+  At present this driver only compiles as a module, so say M here if you
+  have this card.  Then read Documentation/networking/README.sb1000 for
+  information on how to use this module, as it needs special ppp scripts for
+  establishing a connection.  Further documentation and the necessary scripts
+  can be found at:
+
+  http://www.jacksonville.net/~fventuri/
+  http://home.adelphia.net/~siglercm/sb1000.html
+  http://linuxpower.cx/~cable/
+
+  If you don't have this card, of course say N.
+
 Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support
 CONFIG_ACENIC
   Say Y here if you have an Alteon AceNIC or 3Com 3C985 PCI Gigabit
@@ -7216,7 +7235,7 @@ CONFIG_MINIX_FS
   You don't want to use the minix filesystem on your hard disk because
   of certain built-in restrictions, but it is sometimes found on older
   Linux floppy disks. This option will enlarge your kernel by about 
-  25 kB. If unsure, say N.
+  28 kB. If unsure, say N.
 
   If you want to compile this as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
@@ -7242,7 +7261,7 @@ CONFIG_EXT2_FS
   ext2fs is a diskless Linux box which mounts all files over the
   network using NFS (in this case it's sufficient to say Y to "NFS
   filesystem support" below). Saying Y here will enlarge your kernel
-  by about 41 kB.
+  by about 44 kB.
 
   The Ext2fs-Undeletion mini-HOWTO, available via FTP (user:
   anonymous) from ftp://metalab.unc.edu/pub/Linux/docs/HOWTO/mini,
@@ -7430,7 +7449,7 @@ CONFIG_PROC_FS
   that has a program like lynx or netscape), and also on the proc(8)
   manpage ("man 8 proc").
 
-  This option will enlarge your kernel by about 18 KB. Several
+  This option will enlarge your kernel by about 67 KB. Several
   programs depend on this, so everyone should say Y here.
 
 NFS filesystem support
@@ -7723,6 +7742,18 @@ CONFIG_SGI_DISKLABEL
   Say Y to this only if you plan on mounting disks with SGI disklabels.
   This is not required to mount EFS-format CDROMs.
 
+EFS filesystem support (experimental)
+CONFIG_EFS_FS
+  EFS is the filesystem used for CDROMs and filesystems by SGI's IRIX.
+  This implementation only offers read-only access.  If you don't know
+  what all this is about, it's safe to say N.  For more information
+  about EFS see it's homepage at http://aeschi.ch.eu.org/efs.
+
+SGI disklabel support
+CONFIG_SGI_DISKLABEL
+  Say Y to this only if you plan on mounting disks with SGI disklabels.
+  This is not required to mount EFS-format CDROMs.
+
 BSD disklabel (FreeBSD partition tables) support
 CONFIG_BSD_DISKLABEL
   FreeBSD uses its own hard disk partition scheme on your PC. It
@@ -8244,6 +8275,16 @@ CONFIG_NLS_ISO8859_10
   letters that were missing in Latin 4 to cover the entire Nordic
   area.
 
+nls iso8859-14
+CONFIG_NLS_ISO8859_14
+  If you want to display filenames with native language characters
+  from the Microsoft fat filesystem family or from JOLIET CDROMs
+  correctly on the screen, you need to include the appropriate
+  input/output character sets. Say Y here for the Latin 8 character
+  set, which adds the last accented vowels for Welsh (and Manx Gaelic)
+  that were missing in Latin 1. http://linux.speech.cymru.org/
+  has further information.
+
 nls iso8859-15
 CONFIG_NLS_ISO8859_15
   If you want to display filenames with native language characters
@@ -10091,6 +10132,12 @@ CONFIG_AEDSP16_MPU_IRQ
   you compiled aedsp16.o as a module you can specify this parameter as
   'mpu_irq=NN'.
 
+SGI Visual Workstation on-board audio
+CONFIG_SOUND_VWSND
+  Say Y or M if you have an SGI Visual Workstation and you want to
+  be able to use its on-board audio.  Read Documentation/sound/visws
+  for more info on this driver's capabilities.
+
 Ensoniq ES1370 based PCI sound cards
 CONFIG_SOUND_ES1370
   Say Y or M if you have a PCI sound card utilizing the Ensoniq
@@ -11751,31 +11798,6 @@ CONFIG_IRCOMM
   will create two modules called ircomm and ircomm_tty. For more
   information go to http://www.pluto.dti.ne.jp/~thiguchi/irda/
 
-IrLPT Protocol
-CONFIG_IRLPT
-  Say Y here if you want to build support for the IrLPT protocol. If
-  you want to compile it as a module, say M here and read
-  Documentation/modules.txt. IrLPT makes it possible to print
-  documents to IrDA capable printers.
-
-IrLPT Client Protocol 
-CONFIG_IRLPT_CLIENT
-  Say Y here if you want to build support for the IrLPT client
-  protocol. If you want to compile it as a module, say M here and read
-  Documentation/modules.txt. The IrLPT client protocol can be used to
-  print documents to IrDA compatible printers like the HP-5MP, or
-  IrLPT printer adapters like the ACTiSYS IR-100M.
-
-IrLPT Server Protocol 
-CONFIG_IRLPT_SERVER
-  Say Y here if you want to build support for the IrLPT server
-  protocol. If you want to compile it as a module, say M here and read
-  Documentation/modules.txt. The IrLPT server protocol makes it
-  possible to use a Linux machine as an infrared printer server for
-  other laptops. So if your Linux machine has a cable connection to a
-  printer, then other laptops can use the Linux machine to print out 
-  documents using infrared communication.
-
 IrTTY IrDA Device Driver
 CONFIG_IRTTY_SIR
   Say Y here if you want to build support for the IrTTY line
@@ -11870,6 +11892,15 @@ CONFIG_GIRBIL_DONGLE
   by IrTTY. To activate support for Greenwich dongles you will have to
   insert "irattach -d girbil" in the /etc/irda/drivers script.
 
+Adaptec Airport 1000 and 2000 dongle
+CONFIG_AIRPORT_DONGLE
+  Say Y here if you want to build support for the Adaptec Airport 1000
+  and 2000 dongles. If you want to compile it as a module, say M here
+  and read Documentation/modules.txt. The Airport dongle attaches to
+  the normal 9-pin serial port connector, and can currently only be
+  used by IrTTY. To activate support for Airport dongles you will have
+  to insert "irattach -d airport" in the /etc/irda/drivers script.
+
 Parallax Litelink dongle
 CONFIG_LITELINK_DONGLE
   Say Y here if you want to build support for the Parallax Litelink
index ec4b90623b7eefa3d6bd058fbe8fd27f10c75cc9..ec600ff22afb1a93ce13945cbf51b430e5662b15 100644 (file)
@@ -104,7 +104,8 @@ S:  Maintained
 ADVANSYS SCSI DRIVER
 P:     Bob Frey
 M:     Bob Frey <bobf@advansys.com>
-W:     http://www.advansys.com/linux
+W:     http://www.advansys.com/linux.html
+L:     linux-scsi@vger.rutgers.edu
 S:     Maintained
 
 AEDSP16 DRIVER
@@ -808,9 +809,7 @@ L:  linux-net@vger.rutgers.edu
 S:     Supported
 
 STALLION TECHNOLOGIES MULTIPORT SERIAL BOARDS
-P:     Greg Ungerer
 M:     support@stallion.oz.au
-M:     gerg@stallion.com
 W:     http://www.stallion.com
 S:     Supported
 
index cfe9cbf6dd7fd96ab0b9571e34ccf88fafc6ff3b..0a0975bb59c6157bf17567ba8ed55a59fe75e9a1 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 3
-SUBLEVEL = 16
+SUBLEVEL = 17
 EXTRAVERSION =
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
@@ -146,6 +146,10 @@ ifdef CONFIG_PCI
 DRIVERS := $(DRIVERS) drivers/pci/pci.a
 endif
 
+ifdef CONFIG_PCMCIA
+DRIVERS := $(DRIVERS) drivers/pcmcia/pcmcia.o
+endif
+
 ifdef CONFIG_DIO
 DRIVERS := $(DRIVERS) drivers/dio/dio.a
 endif
index b19020f7b22722898b5a0ca64ac94a25321dfd2c..282147e72c1b0bfa69fdb5963fa2648fdbebe6ab 100644 (file)
@@ -16,7 +16,7 @@ all: kernel.o head.o
 
 O_TARGET := kernel.o
 O_OBJS   := entry.o traps.o process.o osf_sys.o irq.o signal.o setup.o \
-           ptrace.o time.o fpreg.o semaphore.o pci_syscall.o
+           ptrace.o time.o fpreg.o semaphore.o
 OX_OBJS  := alpha_ksyms.o
 
 
@@ -28,12 +28,11 @@ O_OBJS       += core_apecs.o core_cia.o core_lca.o core_mcpcia.o core_pyxis.o \
            sys_jensen.o sys_miata.o sys_mikasa.o sys_noritake.o \
            sys_rawhide.o sys_ruffian.o sys_sable.o sys_sio.o \
            sys_sx164.o sys_takara.o sys_rx164.o \
-           es1888.o smc37c669.o smc37c93x.o ns87312.o \
-           pci.o pci_setup.o
+           es1888.o smc37c669.o smc37c93x.o ns87312.o pci.o
 else
 
 ifdef CONFIG_PCI
-O_OBJS   += pci.o pci_setup.o
+O_OBJS   += pci.o
 endif
 
 # Core logic support
index 426a358d638dd19e3825a95a93e1a74fb4a83427..46378b7620ceab0d7bdcb36297f1f4115a1f1fa9 100644 (file)
@@ -11,7 +11,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/pci.h>
 #include <linux/init.h>
index e77b4e84e4c20fc34ae9d8bba58cdd6254521012..5821db09dd803c116b3890b1f6eed65b80d015d6 100644 (file)
@@ -12,7 +12,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/pci.h>
 #include <linux/sched.h>
index 2a5d3eace71d3f19b73840188c28f5dd91994209..13172b708405b605da346cb4813e0a366b34b2a5 100644 (file)
@@ -9,7 +9,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/pci.h>
 #include <linux/init.h>
index a9fcedc307498a8cc72654577cf5550eb88ca3bf..ac86d5255a2e214cb669a8b6fc3b67d691c2ded6 100644 (file)
@@ -6,7 +6,6 @@
  * Code common to all MCbus-PCI Adaptor core logic chipsets
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/pci.h>
index 61d6d66436b9e207c840d72a5e42485f4ef67b4d..88a3e37c9f765ac15806f80c120ed0f7670e854a 100644 (file)
@@ -6,7 +6,6 @@
  * Code common to all PYXIS core logic chips.
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/pci.h>
index 71de59f565c15c5b1beeea766ed8a9d05ea7e914..43103f8ebc1896e2194233901b829c00adba1305 100644 (file)
@@ -9,7 +9,6 @@
  * Code common to all T2 core logic chips.
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/pci.h>
index 3ec95ee9f225ee5ea0a423a144622c071b5f6df0..c0d7c867d28313ea013ea81756ef4216c1f54e43 100644 (file)
@@ -6,7 +6,6 @@
  * Code common to all TSUNAMI core logic chips.
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/pci.h>
index a5597052e0db56e937e3e403d02a77a928047f50..a81ba409304cb0f642bd69e1220c03ea2fdabe41 100644 (file)
@@ -6,7 +6,6 @@
  *     David Mosberger (davidm@cs.arizona.edu)
  */
 
-#include <linux/config.h>
 #include <linux/string.h>
 #include <linux/pci.h>
 #include <linux/init.h>
@@ -70,19 +69,21 @@ struct pci_fixup pcibios_fixups[] __initdata = {
  */
 
 static void __init
-pci_assign_special(void)
+pcibios_assign_special(void)
 {
        struct pci_dev *dev;
-
-       /* The first three resources of the Cypress IDE controler need
-          to remain unchanged.  So allocate them as-is.  */
-       dev = NULL;
-       while ((dev = pci_find_device(PCI_VENDOR_ID_CONTAQ,
-                                      PCI_DEVICE_ID_CONTAQ_82C693, dev))) {
-               if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
-                       pci_record_assignment(dev, 0);
-                       pci_record_assignment(dev, 1);
-                       pci_record_assignment(dev, 2);
+       int i;
+
+       /* The first three resources of an IDE controler are often magic, 
+          so leave them unchanged.  This is true, for instance, of the
+          Contaq 82C693 as seen on SX164 and DP264.  */
+
+       for (dev = pci_devices; dev; dev = dev->next) {
+               if (dev->class >> 8 != PCI_CLASS_STORAGE_IDE)
+                       continue;
+               for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+                       if (dev->resource[i].flags)
+                               pci_claim_resource(dev, i);
                }
        }
 }
@@ -107,40 +108,35 @@ pcibios_fixup_bus(struct pci_bus *bus)
 {
        /* Propogate hose info into the subordinate devices.  */
 
+       struct pci_controler *hose = probing_hose;
        struct pci_dev *dev;
-       void *sysdata;
 
-       sysdata = (bus->parent ? bus->parent->sysdata : bus->sysdata);
+       bus->resource[0] = hose->io_space;
+       bus->resource[1] = hose->mem_space;
        for (dev = bus->devices; dev; dev = dev->sibling)
-               dev->sysdata = sysdata;
+               dev->sysdata = hose;
 }
 
 void __init
-pcibios_base_address_update(struct pci_dev *dev, int resource)
+pcibios_update_resource(struct pci_dev *dev, struct resource *root,
+                       struct resource *res, int resource)
 {
-       struct pci_controler *hose = dev->sysdata;
-        struct resource *res = &dev->resource[resource];
-        unsigned long base, where, size;
+        unsigned long where, size;
         u32 reg;
 
-        if (res->flags & IORESOURCE_IO)
-                base = hose->io_space->start;
-        else
-                base = hose->mem_space->start;
-
         where = PCI_BASE_ADDRESS_0 + (resource * 4);
         size = res->end - res->start;
         pci_read_config_dword(dev, where, &reg);
-        reg = (reg & size) | (((u32)(res->start - base)) & ~size);
+        reg = (reg & size) | (((u32)(res->start - root->start)) & ~size);
         pci_write_config_dword(dev, where, reg);
 
        /* ??? FIXME -- record old value for shutdown.  */
 }
 
 void __init
-pcibios_irq_update(struct pci_dev *dev, u8 irq)
+pcibios_update_irq(struct pci_dev *dev, int irq)
 {
-       pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+       pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
 
        /* ??? FIXME -- record old value for shutdown.  */
 }
@@ -186,10 +182,10 @@ common_init_pci(void)
        }
        probing_hose = NULL;
 
-       pci_assign_special();
-       pci_assign_unassigned(alpha_mv.min_io_address,
-                             alpha_mv.min_mem_address);
-       pci_fixup_irq(alpha_mv.pci_swizzle, alpha_mv.pci_map_irq);
+       pcibios_assign_special();
+       pci_assign_unassigned_resources(alpha_mv.min_io_address,
+                                       alpha_mv.min_mem_address);
+       pci_fixup_irqs(alpha_mv.pci_swizzle, alpha_mv.pci_map_irq);
        pci_set_bus_ranges();
 }
 
index 482ffd41152830be75cd16eb71bfbc8dfc9a81dc..c7c97f0963129551db3294902eee0be2409dccfa 100644 (file)
@@ -127,7 +127,6 @@ static inline u8 bridge_swizzle(u8 pin, u8 slot)
 extern struct pci_controler *hose_head, **hose_tail;
 extern struct pci_controler *probing_hose;
 
-/* pci_common.c */
 extern void common_init_pci(void);
 extern u8 common_swizzle(struct pci_dev *, u8 *);
 extern struct pci_controler *alloc_pci_controler(unsigned long *);
@@ -136,11 +135,3 @@ extern struct resource *alloc_resource(unsigned long *);
 extern const char *const pci_io_names[];
 extern const char *const pci_mem_names[];
 extern const char pci_hae0_name[];
-
-/* pci_setup.c */
-void pci_record_assignment(struct pci_dev *dev, int resource);
-void pci_assign_unassigned(int, int);
-void pci_fixup_irq(u8 (*swizzle)(struct pci_dev *, u8 *),
-                  int (*map_irq)(struct pci_dev *, u8, u8));
-void pci_set_bus_ranges(void);
-
diff --git a/arch/alpha/kernel/pci_setup.c b/arch/alpha/kernel/pci_setup.c
deleted file mode 100644 (file)
index 4799ec5..0000000
+++ /dev/null
@@ -1,328 +0,0 @@
-/*
- *     linux/arch/alpha/kernel/pci_setup.c
- *
- * Extruded from code written by
- *      Dave Rusling (david.rusling@reo.mts.dec.com)
- *      David Mosberger (davidm@cs.arizona.edu)
- *     David Miller (davem@redhat.com)
- */
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/ioport.h>
-#include <asm/pci.h>
-
-
-#define DEBUG_CONFIG 0
-#if DEBUG_CONFIG
-# define DBGC(args)     printk args
-#else
-# define DBGC(args)
-#endif
-
-
-void __init
-pci_record_assignment(struct pci_dev *dev, int resource)
-{
-       struct pci_controler *hose = dev->sysdata;
-        struct resource *res = &dev->resource[resource];
-       struct resource *base;
-       int ok;
-
-       if (res->flags == 0)
-               return;
-       if (res->flags & IORESOURCE_IO)
-               base = hose->io_space;
-       else
-               base = hose->mem_space;
-
-       res->start += base->start;
-       res->end += base->start;
-
-       ok = request_resource(base, res);
-
-       DBGC(("PCI record assignment: (%s) resource %d %s\n",
-             dev->name, resource, (ok < 0 ? "failed" : "ok")));
-}
-
-static void inline
-pdev_assign_unassigned(struct pci_dev *dev, int min_io, int min_mem)
-{
-       u32 reg;
-       u16 cmd;
-       int i;
-
-       DBGC(("PCI assign resources : (%s)\n", dev->name));
-
-       pci_read_config_word(dev, PCI_COMMAND, &cmd);
-
-       for (i = 0; i < PCI_NUM_RESOURCES; i++) {
-               struct pci_controler *hose;
-               struct resource *root, *res;
-               unsigned long size, min, max;
-
-               res = &dev->resource[i];
-
-               if (res->flags & IORESOURCE_IO)
-                       cmd |= PCI_COMMAND_IO;
-               else if (res->flags & IORESOURCE_MEM)
-                       cmd |= PCI_COMMAND_MEMORY;
-
-               /* If it is already assigned or the resource does
-                  not exist, there is nothing to do.  */
-               if (res->parent != NULL || res->flags == 0UL)
-                       continue;
-
-               hose = dev->sysdata;
-
-               /* Determine the root we allocate from.  */
-               if (res->flags & IORESOURCE_IO) {
-                       root = hose->io_space;
-                       min = root->start + min_io;
-                       max = root->end;
-               } else {
-                       root = hose->mem_space;
-                       min = root->start + min_mem;
-                       max = root->end;
-               }
-
-               size = res->end - res->start + 1;
-
-               DBGC(("  for root[%016lx:%016lx]\n"
-                     "       res[%016lx:%016lx]\n"
-                     "      span[%016lx:%016lx] size[%lx]\n",
-                     root->start, root->end, res->start, res->end,
-                     min, max, size));
-
-               if (allocate_resource(root, res, size, min, max, size) < 0) {
-                       printk(KERN_ERR
-                              "PCI: Failed to allocate resource %d for %s\n",
-                              i, dev->name);
-               }
-
-               DBGC(("  got res[%016lx:%016lx] for resource %d\n",
-                     res->start, res->end, i));
-
-               /* Update PCI config space.  */
-               pcibios_base_address_update(dev, i);
-       }
-
-       /* Special case, disable the ROM.  Several devices act funny
-          (ie. do not respond to memory space writes) when it is left
-          enabled.  A good example are QlogicISP adapters.  */
-
-       pci_read_config_dword(dev, PCI_ROM_ADDRESS, &reg);
-       reg &= ~PCI_ROM_ADDRESS_ENABLE;
-       pci_write_config_dword(dev, PCI_ROM_ADDRESS, reg);
-
-       /* All of these (may) have I/O scattered all around and may not
-          use IO-base address registers at all.  So we just have to
-          always enable IO to these devices.  */
-       if ((dev->class >> 8) == PCI_CLASS_NOT_DEFINED
-           || (dev->class >> 8) == PCI_CLASS_NOT_DEFINED_VGA
-           || (dev->class >> 8) == PCI_CLASS_STORAGE_IDE
-           || (dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
-               cmd |= PCI_COMMAND_IO;
-       }
-
-       /* ??? Always turn on bus mastering.  */
-       cmd |= PCI_COMMAND_MASTER;
-
-       /* Enable the appropriate bits in the PCI command register.  */
-       pci_write_config_word(dev, PCI_COMMAND, cmd);
-
-       DBGC(("  cmd reg 0x%x\n", cmd));
-
-       /* If this is a PCI bridge, set the cache line correctly.  */
-       if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
-               /* ??? EV4/EV5 cache line is 32 bytes.  */
-               pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
-                                     (64 / sizeof(u32)));
-       }
-}
-
-void __init
-pci_assign_unassigned(int min_io, int min_mem)
-{
-       struct pci_dev *dev;
-
-       for (dev = pci_devices; dev; dev = dev->next)
-               pdev_assign_unassigned(dev, min_io, min_mem);
-}
-
-struct pbus_set_ranges_data
-{
-       int found_vga;
-       unsigned int io_start, io_end;
-       unsigned int mem_start, mem_end;
-};
-
-static void __init
-pbus_set_ranges(struct pci_bus *bus, struct pbus_set_ranges_data *outer)
-{
-       struct pbus_set_ranges_data inner;
-       struct pci_bus *child;
-       struct pci_dev *dev;
-
-       inner.found_vga = 0;
-       inner.mem_start = inner.io_start = ~0;
-       inner.mem_end = inner.io_end = 0;
-
-       /* Collect information about how our direct children are layed out. */
-       for (dev = bus->devices; dev; dev = dev->sibling) {
-               int i;
-               for (i = 0; i < PCI_NUM_RESOURCES; i++) {
-                       struct resource *res = &dev->resource[i];
-                       if (res->flags & IORESOURCE_IO) {
-                               if (res->start < inner.io_start)
-                                       inner.io_start = res->start;
-                               if (res->end > inner.io_end)
-                                       inner.io_end = res->end;
-                       } else if (res->flags & IORESOURCE_MEM) {
-                               if (res->start < inner.mem_start)
-                                       inner.mem_start = res->start;
-                               if (res->end > inner.mem_end)
-                                       inner.mem_end = res->end;
-                       }
-               }
-                if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA)
-                        inner.found_vga = 1;
-       }
-
-       /* And for all of the sub-busses.  */
-       for (child = bus->children; child; child = child->next)
-               pbus_set_ranges(child, &inner);
-
-       /* Align the values.  */
-       inner.io_start &= ~(4*1024 - 1);
-       inner.mem_start &= ~(1*1024*1024 - 1);
-       if (inner.io_end & (4*1024-1))
-               inner.io_end = (inner.io_end | (4*1024 - 1)) + 1;
-       if (inner.mem_end & (1*1024*1024-1))
-               inner.mem_end = (inner.mem_end | (1*1024*1024 - 1)) + 1;
-
-       /* Configure the bridge, if possible.  */
-       if (bus->self) {
-               struct pci_dev *bridge = bus->self;
-               u32 l;
-
-                /* Set up the top and bottom of the PCI I/O segment
-                   for this bus.  */
-                pci_read_config_dword(bridge, PCI_IO_BASE, &l);
-                l &= 0xffff0000;
-                l |= (inner.io_start >> 8) & 0x00f0;
-               l |= (inner.io_end - 1) & 0xf000;
-                pci_write_config_dword(bridge, PCI_IO_BASE, l);
-
-                /*
-                 * Clear out the upper 16 bits of IO base/limit.
-                 * Clear out the upper 32 bits of PREF base/limit.
-                 */
-                pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, 0);
-                pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, 0);
-                pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0);
-
-                /* Set up the top and bottom of the PCI Memory segment
-                   for this bus.  */
-                l = (inner.mem_start & 0xfff00000) >> 16;
-               l |= (inner.mem_end - 1) & 0xfff00000;
-                pci_write_config_dword(bridge, PCI_MEMORY_BASE, l);
-
-                /*
-                 * Turn off downstream PF memory address range, unless
-                 * there is a VGA behind this bridge, in which case, we
-                 * enable the PREFETCH range to include BIOS ROM at C0000.
-                 *
-                 * NOTE: this is a bit of a hack, done with PREFETCH for
-                 * simplicity, rather than having to add it into the above
-                 * non-PREFETCH range, which could then be bigger than we want.
-                 * We might assume that we could relocate the BIOS ROM, but
-                 * that would depend on having it found by those who need it
-                 * (the DEC BIOS emulator would find it, but I do not know
-                 * about the Xservers). So, we do it this way for now... ;-)
-                 */
-                l = (inner.found_vga) ? 0 : 0x0000ffff;
-                pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l);
-
-                /*
-                 * Tell bridge that there is an ISA bus in the system,
-                 * and (possibly) a VGA as well.
-                 */
-                l = (inner.found_vga) ? 0x0c : 0x04;
-                pci_write_config_byte(bridge, PCI_BRIDGE_CONTROL, l);
-
-                /*
-                 * Clear status bits,
-                 * turn on I/O    enable (for downstream I/O),
-                 * turn on memory enable (for downstream memory),
-                 * turn on master enable (for upstream memory and I/O).
-                 */
-                pci_write_config_dword(bridge, PCI_COMMAND, 0xffff0007);
-       }
-
-       if (outer) {
-               outer->found_vga |= inner.found_vga;
-               if (inner.io_start < outer->io_start)
-                       outer->io_start = inner.io_start;
-               if (inner.io_end > outer->io_end)
-                       outer->io_end = inner.io_end;
-               if (inner.mem_start < outer->mem_start)
-                       outer->mem_start = inner.mem_start;
-               if (inner.mem_end > outer->mem_end)
-                       outer->mem_end = inner.mem_end;
-       }
-}
-
-void __init
-pci_set_bus_ranges(void)
-{
-       struct pci_bus *bus;
-
-       for (bus = pci_root; bus; bus = bus->next)
-               pbus_set_ranges(bus, NULL);
-}
-
-static void inline
-pdev_fixup_irq(struct pci_dev *dev,
-              u8 (*swizzle)(struct pci_dev *, u8 *),
-              int (*map_irq)(struct pci_dev *, u8, u8))
-{
-       u8 pin, slot;
-       int irq;
-
-       /* If this device is not on the primary bus, we need to figure out
-          which interrupt pin it will come in on.   We know which slot it
-          will come in on 'cos that slot is where the bridge is.   Each
-          time the interrupt line passes through a PCI-PCI bridge we must
-          apply the swizzle function.  */
-
-       pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
-       /* Cope with 0 and illegal. */
-       if (pin == 0 || pin > 4)
-               pin = 1;
-
-       /* Follow the chain of bridges, swizzling as we go.  */
-       slot = (*swizzle)(dev, &pin);
-
-       irq = (*map_irq)(dev, slot, pin);
-       if (irq == -1)
-               irq = 0;
-       dev->irq = irq;
-
-       DBGC(("PCI fixup irq : (%s) got %d\n", dev->name, dev->irq));
-
-       /* Always tell the device, so the driver knows what is
-          the real IRQ to use; the device does not use it. */
-       pcibios_irq_update(dev, irq);
-}
-
-void __init
-pci_fixup_irq(u8 (*swizzle)(struct pci_dev *, u8 *),
-             int (*map_irq)(struct pci_dev *, u8, u8))
-{
-       struct pci_dev *dev;
-
-       for (dev = pci_devices; dev; dev = dev->next)
-               pdev_fixup_irq(dev, swizzle, map_irq);
-}
diff --git a/arch/alpha/kernel/pci_syscall.c b/arch/alpha/kernel/pci_syscall.c
deleted file mode 100644 (file)
index 8d9c0c4..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- *     pci_syscall.c
- */
-
-#include <linux/config.h>
-#include <linux/errno.h>
-#include <linux/pci.h>
-#include <linux/smp_lock.h>
-#include <asm/uaccess.h>
-
-
-#ifndef CONFIG_PCI
-
-asmlinkage int sys_pciconfig_read() { return -ENOSYS; }
-asmlinkage int sys_pciconfig_write() { return -ENOSYS; }
-
-#else
-
-asmlinkage long
-sys_pciconfig_read(unsigned long bus, unsigned long dfn,
-                  unsigned long off, unsigned long len, void *buf)
-{
-       struct pci_dev *dev;
-       u8 byte;
-       u16 word;
-       u32 dword;
-       long err, cfg_ret;
-
-       err = -EPERM;
-       if (!capable(CAP_SYS_ADMIN))
-               goto error;
-
-       err = -ENODEV;
-       dev = pci_find_slot(bus, dfn);
-       if (!dev)
-               goto error;
-
-       lock_kernel();
-       switch (len) {
-       case 1:
-               cfg_ret = pci_read_config_byte(dev, off, &byte);
-               break;
-       case 2:
-               cfg_ret = pci_read_config_word(dev, off, &word);
-               break;
-       case 4:
-               cfg_ret = pci_read_config_dword(dev, off, &dword);
-               break;
-       default:
-               err = -EINVAL;
-               unlock_kernel();
-               goto error;
-       };
-       unlock_kernel();
-
-       err = -EIO;
-       if (cfg_ret != PCIBIOS_SUCCESSFUL)
-               goto error;
-
-       switch (len) {
-       case 1:
-               err = put_user(byte, (unsigned char *)buf);
-               break;
-       case 2:
-               err = put_user(word, (unsigned short *)buf);
-               break;
-       case 4:
-               err = put_user(dword, (unsigned int *)buf);
-               break;
-       };
-       return err;
-
-error:
-       /* ??? XFree86 doesn't even check the return value.  They
-          just look for 0xffffffff in the output, since that's what
-          they get instead of a machine check on x86.  */
-       switch (len) {
-       case 1:
-               put_user(-1, (unsigned char *)buf);
-               break;
-       case 2:
-               put_user(-1, (unsigned short *)buf);
-               break;
-       case 4:
-               put_user(-1, (unsigned int *)buf);
-               break;
-       };
-       return err;
-}
-
-asmlinkage long
-sys_pciconfig_write(unsigned long bus, unsigned long dfn,
-                   unsigned long off, unsigned long len, void *buf)
-{
-       struct pci_dev *dev;
-       u8 byte;
-       u16 word;
-       u32 dword;
-       int err = 0;
-
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-       if (!pcibios_present())
-               return -ENOSYS;
-
-       dev = pci_find_slot(bus, dfn);
-       if (!dev)
-               return -ENODEV;
-
-       lock_kernel();
-       switch(len) {
-       case 1:
-               err = get_user(byte, (u8 *)buf);
-               if (err)
-                       break;
-               err = pci_write_config_byte(dev, off, byte);
-               if (err != PCIBIOS_SUCCESSFUL)
-                       err = -EIO;
-               break;
-
-       case 2:
-               err = get_user(word, (u16 *)buf);
-               if (err)
-                       break;
-               err = pci_write_config_byte(dev, off, word);
-               if (err != PCIBIOS_SUCCESSFUL)
-                       err = -EIO;
-               break;
-
-       case 4:
-               err = get_user(dword, (u32 *)buf);
-               if (err)
-                       break;
-               pci_write_config_byte(dev, off, dword);
-               if (err != PCIBIOS_SUCCESSFUL)
-                       err = -EIO;
-               break;
-
-       default:
-               err = -EINVAL;
-               break;
-       };
-       unlock_kernel();
-
-       return err;
-}
-
-#endif /* CONFIG_PCI */
index 476928a84b24268170765efcd18956c6d4456a2e..1b5e1c3cf6c1cb6951d79ae85fb7c6ab2dd5b066 100644 (file)
@@ -24,7 +24,6 @@
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/core_mcpcia.h>
-#include <asm/pci.h>
 
 #include "proto.h"
 #include "irq_impl.h"
index fdf58d028166cd3b6923ad9d83c5d1370d9cb2d3..35bb0a36ad49b9834887d32097b6aaa71058d13b 100644 (file)
@@ -5,7 +5,6 @@
  *
  * Bits taken from various places.
  */
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/init.h>
index 1e14b9b2be3a3beb58e63f95f8f2cc417ad1fb3d..aecc223af06af463f3febc4219f6e11f90c01ed6 100644 (file)
@@ -6,7 +6,6 @@
  * These are the low level assembler for performing cache and TLB
  * functions on the sa110.
  */
-#include <linux/config.h>
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 #include <asm/procinfo.h>
index 3c6e83f81b067b0136db96a615b5e514ee92494d..136034f6f8c9006dbad62a39d2f36e9b30c17cb6 100644 (file)
@@ -5,6 +5,7 @@
 mainmenu_name "Linux Kernel Configuration"
 
 define_bool CONFIG_X86 y
+define_bool CONFIG_ISA y
 
 mainmenu_option next_comment
 comment 'Code maturity level options'
@@ -83,6 +84,8 @@ else
   fi
 fi
 
+source drivers/pcmcia/Config.in
+
 bool 'System V IPC' CONFIG_SYSVIPC
 bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
 bool 'Sysctl support' CONFIG_SYSCTL
index f639c173f02d518f144f1c51bd06ad29ee69d3f2..2c100ead305969267f6c63f1dee4fba0834e0b60 100644 (file)
@@ -2,6 +2,7 @@
 # Automatically generated make config: don't edit
 #
 CONFIG_X86=y
+CONFIG_ISA=y
 
 #
 # Code maturity level options
@@ -50,6 +51,12 @@ CONFIG_PCI_DIRECT=y
 # CONFIG_VISWS is not set
 CONFIG_X86_IO_APIC=y
 CONFIG_X86_LOCAL_APIC=y
+
+#
+# PCMCIA/Cardbus support
+#
+CONFIG_PCMCIA=y
+CONFIG_CARDBUS=y
 CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
@@ -373,6 +380,8 @@ CONFIG_EXT2_FS=y
 #
 # CONFIG_CODA_FS is not set
 CONFIG_NFS_FS=y
+CONFIG_NFSD=y
+# CONFIG_NFSD_SUN is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 # CONFIG_SMB_FS is not set
index d5b900f55a545493e0eba2fbf8488c7223f64bc3..a797789898f7e2e916d13b7c235bc7c2fb833dfe 100644 (file)
@@ -1391,7 +1391,7 @@ static int apm(void *unused)
                }
        }
 #endif
-       if (((apm_bios_info.flags & APM_BIOS_DISABLED) == 0)
+       if (((apm_bios_info.flags & APM_BIOS_DISENGAGED) == 0)
            && (apm_bios_info.version > 0x0100)) {
                if (apm_engage_power_management(0x0001) == APM_SUCCESS)
                        apm_bios_info.flags &= ~APM_BIOS_DISENGAGED;
index aa623624999512b2d442e68b07db74df663b58bd..1d0125738b5669032e0588ce69e47a78ce1fff31 100644 (file)
@@ -266,14 +266,14 @@ static char command_line[COMMAND_LINE_SIZE] = { 0, };
        char saved_command_line[COMMAND_LINE_SIZE];
 
 struct resource standard_io_resources[] = {
-       { "dma1", 0x00, 0x1f },
-       { "pic1", 0x20, 0x3f },
-       { "timer", 0x40, 0x5f },
-       { "keyboard", 0x60, 0x6f },
-       { "dma page reg", 0x80, 0x8f },
-       { "pic2", 0xa0, 0xbf },
-       { "dma2", 0xc0, 0xdf },
-       { "fpu", 0xf0, 0xff }
+       { "dma1", 0x00, 0x1f, IORESOURCE_BUSY },
+       { "pic1", 0x20, 0x3f, IORESOURCE_BUSY },
+       { "timer", 0x40, 0x5f, IORESOURCE_BUSY },
+       { "keyboard", 0x60, 0x6f, IORESOURCE_BUSY },
+       { "dma page reg", 0x80, 0x8f, IORESOURCE_BUSY },
+       { "pic2", 0xa0, 0xbf, IORESOURCE_BUSY },
+       { "dma2", 0xc0, 0xdf, IORESOURCE_BUSY },
+       { "fpu", 0xf0, 0xff, IORESOURCE_BUSY }
 };
 
 #define STANDARD_IO_RESOURCES (sizeof(standard_io_resources)/sizeof(struct resource))
@@ -284,7 +284,7 @@ struct resource standard_io_resources[] = {
 static struct resource ram_resources[] = {
        { "System RAM", 0x000000, 0x09ffff, IORESOURCE_BUSY },
        { "System RAM", 0x100000, 0x100000, IORESOURCE_BUSY },
-       { "Video RAM area", 0x0a0000, 0x0bffff },
+       { "Video RAM area", 0x0a0000, 0x0bffff, IORESOURCE_BUSY },
        { "Kernel code", 0x100000, 0 },
        { "Kernel data", 0, 0 }
 };
@@ -293,7 +293,7 @@ static struct resource ram_resources[] = {
 #define MAXROMS 6
 static struct resource rom_resources[MAXROMS] = {
        { "System ROM", 0xF0000, 0xFFFFF, IORESOURCE_BUSY },
-       { "Video ROM", 0xc0000, 0xc7fff }
+       { "Video ROM", 0xc0000, 0xc7fff, IORESOURCE_BUSY }
 };
 
 #define romsignature(x) (*(unsigned short *)(x) == 0xaa55)
@@ -337,6 +337,7 @@ static void __init probe_roms(void)
                                rom_resources[roms].start = base;
                                rom_resources[roms].end = base + length - 1;
                                rom_resources[roms].name = "Extension ROM";
+                               rom_resources[roms].flags = IORESOURCE_BUSY;
 
                                request_resource(&iomem_resource, rom_resources + roms);
                                roms++;
@@ -354,6 +355,7 @@ static void __init probe_roms(void)
                rom_resources[roms].start = base;
                rom_resources[roms].end = base + 65535;
                rom_resources[roms].name = "Extension ROM";
+               rom_resources[roms].flags = IORESOURCE_BUSY;
 
                request_resource(&iomem_resource, rom_resources + roms);
        }
@@ -528,6 +530,10 @@ void __init setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigne
 
        memory_end = 0;
        for (i=0; i < e820.nr_map; i++) {
+               printk("type=%d, addr=%08x, size=%08x",
+                       e820.map[i].type,
+                       e820.map[i].addr,
+                       e820.map[i].size);
                /* RAM? */
                if (e820.map[i].type == 1) {
                        unsigned long end = e820.map[i].addr + e820.map[i].size;
index 605a481df1d5c96a43dbc2a4c6418f651ff30f7f..a9995ab8fc44ac2fd35b40685af9e9fac0f887b5 100644 (file)
@@ -67,8 +67,8 @@ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
 { \
        tsk->thread.error_code = error_code; \
        tsk->thread.trap_no = trapnr; \
-       force_sig(signr, tsk); \
        die_if_no_fixup(str,regs,error_code); \
+       force_sig(signr, tsk); \
 }
 
 #define DO_VM86_ERROR(trapnr, signr, str, name, tsk) \
index 26358b9cbfdebdf08758dfb2cdb0d55af906c2ba..0264b8aa476a77b71873e2c070ccfec4bdb4244b 100644 (file)
@@ -16,7 +16,7 @@
  * Head.S contains the MIPS exception handler and startup code.
  */
 #include <linux/config.h>
-#include <linux/tasks.h>
+#include <linux/threads.h>
 
 #include <asm/asm.h>
 #include <asm/cacheops.h>
index 069d764fe86d16ed3d7a2eae6885a140ab31df7f..095f50e8fdbb14102cb5d00de8f6a0325cc01ce8 100644 (file)
@@ -10,7 +10,6 @@
 
 #include "ppc_asm.tmpl"
 #include "ppc_defs.h"
-#include <linux/config.h>
 #include <asm/processor.h>
 #include <asm/page.h>
 #include <asm/gemini.h>
index e857efe50830b5388d293af04a84f390f9750d82..0f0222a6b5316a96c0771bccf9b09a224f5ed77f 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/errno.h> 
 #include <linux/reboot.h>
 #include <linux/pci.h>
-#include <linux/stddef.h>
 #include <linux/kdev_t.h>
 #include <linux/types.h>
 #include <linux/major.h>
index 7a9eb05d21a984e4f40a4d3076aab5bb060fe476..2eae049e5beccf4ef70e9fc934ae2162c05b1fb6 100644 (file)
@@ -7,7 +7,6 @@
  *
  */
 
-#include <linux/config.h>
 #include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/kernel_stat.h>
index 5113f656e83694b337f2bb6fdcb42822222e08e3..744da694b6ed206887d935ecfb4ff8d6317dba22 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/user.h>
 #include <linux/a.out.h>
 #include <linux/interrupt.h>
-#include <linux/config.h>
 #include <linux/unistd.h>
 #include <linux/delay.h>
 #include <linux/reboot.h>
index e18e45c09fc696aa13a7d14eb514fd5229da369d..2d69b5b7c4884bdb933e3efa6b0e80ba5f3933bc 100644 (file)
@@ -3,7 +3,6 @@
  * linux/arch/sh/kernel/ptrace.c
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
index 4fcd93f93931b4a970ef261b3689cdc828c59858..6f4598a7e0abb7bb6481951be703d9a3565dc30a 100644 (file)
@@ -26,7 +26,6 @@
 #include <asm/delay.h>
 
 #include <linux/timex.h>
-#include <linux/config.h>
 #include <linux/irq.h>
 
 #define TMU_TOCR       0xfffffe90      /* Byte access */
index d2662a56acfbf68b25d5f13ca269c0f1b3df43f8..2e75d360460279aa4267e0abec77a298e213ef3f 100644 (file)
@@ -8,7 +8,6 @@
  * 'Traps.c' handles hardware traps and faults after we have saved some
  * state in 'entry.S'.
  */
-#include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
index 06129094061934dfc0c4434dc1031cce00d053ff..c1348d5b4a3c6072385cbdbda46dfafa747ec73e 100644 (file)
@@ -23,7 +23,6 @@
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/hardirq.h>
-#include <asm/uaccess.h>       /* to get __m() macro */
 #include <asm/mmu_context.h>
 
 extern void die(const char *,struct pt_regs *,long);
index bd71aedec6b04fdadfe7249af17d6545e97f2243..a812c91f8f61dad9bf4016cce06aeac6a3401f83 100644 (file)
@@ -1,6 +1,7 @@
 /* ld script to make SuperH Linux kernel
  * Written by Niibe Yutaka
  */
+#include <linux/config.h>
 #ifdef CONFIG_LITTLE_ENDIAN
 OUTPUT_FORMAT("elf32-shl", "elf32-shl", "elf32-shl")
 #else
index 89e33174de4a651ea36c2f71ba48da493fffc873..088df765c46049410eb9139116e568af0d87ee04 100644 (file)
@@ -17,7 +17,7 @@
 #include <asm/irq.h>
 #include <asm/pgtable.h>
 #include <asm/ap1000/pgtapmmu.h>
-#include <linux/tasks.h>
+#include <linux/threads.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
 
index 455a67173ce47c73fd849afd2c0701721bd3be31..2f8a7cd34e12baa07528276cd25cef805f2ea8bc 100644 (file)
@@ -10,7 +10,7 @@
 #include <asm/ap1000/apreg.h>
 #include <linux/mm.h>
 #include <linux/sched.h>
-#include <linux/tasks.h>
+#include <linux/threads.h>
 
 extern int cap_cid0;
 extern unsigned _ncel, _ncelx, _ncely, _cid;
index fbf79acbe57cefa5aba6306d0cda2b53ef31828f..fdc9d49df9ac1d3e22df6b03b588844d78a58cea 100644 (file)
@@ -8,7 +8,7 @@
 
 #include <linux/kernel.h>
 #include <linux/sched.h>
-#include <linux/tasks.h>
+#include <linux/threads.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/interrupt.h>
index 5147985f11d7c7df41fba79f09032a3b219d8c0e..a749f760eb7432e2f5bf895e159ee167d9b10269 100644 (file)
@@ -11,7 +11,7 @@
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
-#include <linux/tasks.h>
+#include <linux/threads.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/interrupt.h>
index 0c906dfdcf98ce4eea1c4792e4aa42f10ec5f559..ba774557f28c1a97efda09bedc070b53febc9903 100644 (file)
@@ -7,7 +7,7 @@
 
 #include <linux/kernel.h>
 #include <linux/sched.h>
-#include <linux/tasks.h>
+#include <linux/threads.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/interrupt.h>
index b0043f6d9e9c226532c56f99bb6b5692b198a586..d8085bf064fc789fdc8767a49e806b926a91ebcf 100644 (file)
@@ -5,7 +5,7 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/tasks.h>
+#include <linux/threads.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
 
index 3a1cbcaaf8ea6d05105caae3e8bc591f5acd8e36..feb56ef4bcc37517d569fd669a9966763246af39 100644 (file)
@@ -6,6 +6,7 @@
  * Copyright (C) 1999 Jakub Jelinek   (jj@ultra.linux.cz)
  */
 
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/sched.h>
index 341e9214f366602802e47ab43fbc8d7f384f8b94..c312db206afa2a04b411c22e2a2f630b2ccd1c9a 100644 (file)
@@ -7,7 +7,7 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/pagemap.h>
-#include <linux/tasks.h>
+#include <linux/threads.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/interrupt.h>
index 8c54674b483f5e411775cf1ff1dbc28963362f8a..28542ded07fd202f010989e7fe905886a1e17f5f 100644 (file)
@@ -22,6 +22,10 @@ ifdef CONFIG_PCI
 SUB_DIRS += pci
 endif
 
+ifdef CONFIG_PCMCIA
+SUB_DIRS += pcmcia
+endif
+
 ifdef CONFIG_SBUS
 SUB_DIRS += sbus
 MOD_SUB_DIRS += sbus
index 9ce38e92150a3759fb96704c6f8657d3d3ee702c..45150379375a5bd7ad7d4399013d0cc23c303ac0 100644 (file)
@@ -4384,7 +4384,7 @@ static void __init parse_floppy_cfg_string(char *cfg)
        }
 }
 
-static void __init mod_setup(char *pattern, void (*setup)(char *))
+static void __init mod_setup(char *pattern, int (*setup)(char *))
 {
        unsigned long i;
        char c;
index 29d4c4cace6e5555f839d8d55fb6d6425aa67a43..b61f7168727ef57ccae6839754f4e67109e8b225 100644 (file)
@@ -466,8 +466,8 @@ unsigned int __init pci_init_hpt366 (struct pci_dev *dev, const char *name)
        byte ata66 = 0;
 
        pci_read_config_byte(dev, 0x5a, &ata66);
-       if (dev->rom_address)
-               pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->rom_address | PCI_ROM_ADDRESS_ENABLE);
+       if (dev->resource[PCI_ROM_RESOURCE].start)
+               pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
        printk("%s: reg5ah=0x%02x ATA-%s Cable Port%d\n", name, ata66, (ata66 & 0x02) ? "33" : "66", PCI_FUNC(dev->devfn));
        return dev->irq;
 }
index 9843677908a2f1fe697bd3d88a2306702597c01c..bbe3dada0f453e557965cb33eceee7d8d28c3ab6 100644 (file)
@@ -1247,20 +1247,10 @@ static void cdrom_pc_intr (ide_drive_t *drive)
 
        /* Figure out how much data to transfer. */
        thislen = pc->buflen;
-       if (thislen < 0) thislen = -thislen;
        if (thislen > len) thislen = len;
 
        /* The drive wants to be written to. */
        if ((ireason & 3) == 0) {
-               /* Check that we want to write. */
-               if (pc->buflen > 0) {
-                       printk ("%s: cdrom_pc_intr: Drive wants "
-                               "to transfer data the wrong way!\n",
-                               drive->name);
-                       pc->stat = 1;
-                       thislen = 0;
-               }
-
                /* Transfer the data. */
                atapi_output_bytes (drive, pc->buffer, thislen);
 
@@ -1274,19 +1264,11 @@ static void cdrom_pc_intr (ide_drive_t *drive)
 
                /* Keep count of how much data we've moved. */
                pc->buffer += thislen;
-               pc->buflen += thislen;
+               pc->buflen -= thislen;
        }
 
        /* Same drill for reading. */
        else if ((ireason & 3) == 2) {
-               /* Check that we want to read. */
-               if (pc->buflen < 0) {
-                       printk ("%s: cdrom_pc_intr: Drive wants to "
-                               "transfer data the wrong way!\n",
-                               drive->name);
-                       pc->stat = 1;
-                       thislen = 0;
-               }
 
                /* Transfer the data. */
                atapi_input_bytes (drive, pc->buffer, thislen);
@@ -1333,11 +1315,8 @@ static void cdrom_do_packet_command (ide_drive_t *drive)
        struct cdrom_info *info = drive->driver_data;
 
        info->dma = 0;
-
-       len = pc->buflen;
-       if (len < 0) len = -len;
-
        pc->stat = 0;
+       len = pc->buflen;
 
        /* Start sending the command to the drive. */
        cdrom_start_packet_command (drive, len, cdrom_do_pc_continuation);
@@ -1794,10 +1773,13 @@ cdrom_read_toc (ide_drive_t *drive,
        toc->xa_flag = (ms_tmp.hdr.first_track != ms_tmp.hdr.last_track);
 
        /* Now try to get the total cdrom capacity. */
+#if 0
        stat = cdrom_get_last_written(MKDEV(HWIF(drive)->major,
                                      drive->select.b.unit << PARTN_BITS),
                                     (long *)&toc->capacity);
-       if (stat) stat = cdrom_read_capacity (drive, &toc->capacity, reqbuf);
+       if (stat)
+#endif
+       stat = cdrom_read_capacity (drive, &toc->capacity, reqbuf);
        if (stat) toc->capacity = 0x1fffff;
 
        HWIF(drive)->gd->sizes[drive->select.b.unit << PARTN_BITS]
@@ -1863,7 +1845,7 @@ cdrom_mode_select (ide_drive_t *drive, int pageno, char *buf, int buflen,
        pc.sense_data = reqbuf;
 
        pc.buffer =  buf;
-       pc.buflen = buflen;
+       pc.buflen = buflen;
        pc.c[0] = GPCMD_MODE_SELECT_10;
        pc.c[1] = 0x10;
        pc.c[2] = pageno;
@@ -2048,7 +2030,6 @@ static int ide_cdrom_packet(struct cdrom_device_info *cdi,
        return cgc->stat;
 }
 
-
 static
 int ide_cdrom_dev_ioctl (struct cdrom_device_info *cdi,
                         unsigned int cmd, unsigned long arg)
@@ -2977,11 +2958,3 @@ int ide_cdrom_init (void)
        MOD_DEC_USE_COUNT;
        return 0;
 }
-
-
-/*==========================================================================*/
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
index 93e583226474c717a0ac7f6a6e60411c48144b66..45f91b2da2a56eb067b2c47a8577d83af8704fcb 100644 (file)
  * Make real block number available to downstream transfer functions, enables
  * CBC (and relatives) mode encryption requiring unique IVs per data block. 
  * Reed H. Petty, rhp@draper.net
+ *
+ * Maximum number of loop devices now dynamic via max_loop module parameter.
+ * Still fixed at 8 devices when compiled into the kernel normally.
+ * Russell Kroll <rkroll@exploits.org> 19990701
  * 
  * Still To Fix:
  * - Advisory locking is ignored here. 
 #define TIMEOUT_VALUE (6 * HZ)
 #include <linux/blk.h>
 
-#define MAX_LOOP 8
-static struct loop_device loop_dev[MAX_LOOP];
-static int loop_sizes[MAX_LOOP];
-static int loop_blksizes[MAX_LOOP];
+#include <linux/malloc.h>
+static int max_loop = 8;
+static struct loop_device *loop_dev;
+static int *loop_sizes;
+static int *loop_blksizes;
 
 #define FALSE 0
 #define TRUE (!FALSE)
@@ -169,7 +174,7 @@ repeat:
        INIT_REQUEST;
        current_request=CURRENT;
        CURRENT=current_request->next;
-       if (MINOR(current_request->rq_dev) >= MAX_LOOP)
+       if (MINOR(current_request->rq_dev) >= max_loop)
                goto error_out;
        lo = &loop_dev[MINOR(current_request->rq_dev)];
        if (!lo->lo_dentry || !lo->transfer)
@@ -578,7 +583,7 @@ static int lo_ioctl(struct inode * inode, struct file * file,
                return -ENODEV;
        }
        dev = MINOR(inode->i_rdev);
-       if (dev >= MAX_LOOP)
+       if (dev >= max_loop)
                return -ENODEV;
        lo = &loop_dev[dev];
        switch (cmd) {
@@ -615,7 +620,7 @@ static int lo_open(struct inode *inode, struct file *file)
                return -ENODEV;
        }
        dev = MINOR(inode->i_rdev);
-       if (dev >= MAX_LOOP) {
+       if (dev >= max_loop) {
                return -ENODEV;
        }
        lo = &loop_dev[dev];
@@ -640,7 +645,7 @@ static int lo_release(struct inode *inode, struct file *file)
                return 0;
        }
        dev = MINOR(inode->i_rdev);
-       if (dev >= MAX_LOOP)
+       if (dev >= max_loop)
                return 0;
        err = fsync_dev(inode->i_rdev);
        lo = &loop_dev[dev];
@@ -674,6 +679,8 @@ static struct file_operations lo_fops = {
  */
 #ifdef MODULE
 #define loop_init init_module
+MODULE_PARM(max_loop, "i");
+MODULE_PARM_DESC(max_loop, "Maximum number of loop devices (1-255)");
 #endif
 
 int loop_register_transfer(struct loop_func_table *funcs)
@@ -690,7 +697,7 @@ int loop_unregister_transfer(int number)
 
        if ((unsigned)number >= MAX_LO_CRYPT)
                return -EINVAL; 
-       for (lo = &loop_dev[0]; lo < &loop_dev[MAX_LOOP]; lo++) { 
+       for (lo = &loop_dev[0]; lo < &loop_dev[max_loop]; lo++) { 
                int type = lo->lo_encrypt_type;
                if (type == number) { 
                        xfer_funcs[type]->release(lo);
@@ -714,17 +721,46 @@ int __init loop_init(void)
                       MAJOR_NR);
                return -EIO;
        }
+
+       if ((max_loop < 1) || (max_loop > 255)) {
+               printk (KERN_WARNING "loop: max_loop must be between 1 and 255\n");
+               return -EINVAL;
+       }
+
 #ifndef MODULE
        printk(KERN_INFO "loop: registered device at major %d\n", MAJOR_NR);
+#else
+       printk(KERN_INFO "loop: enabling %d loop devices\n", max_loop);
 #endif
 
+       loop_dev = kmalloc (max_loop * sizeof(struct loop_device), GFP_KERNEL);
+       if (!loop_dev) {
+               printk (KERN_ERR "loop: Unable to create loop_dev\n");
+               return -ENOMEM;
+       }
+
+       loop_sizes = kmalloc(max_loop * sizeof(int), GFP_KERNEL);
+       if (!loop_sizes) {
+               printk (KERN_ERR "loop: Unable to create loop_sizes\n");
+               kfree (loop_dev);
+               return -ENOMEM;
+       }
+
+       loop_blksizes = kmalloc (max_loop * sizeof(int), GFP_KERNEL);
+       if (!loop_blksizes) {
+               printk (KERN_ERR "loop: Unable to create loop_blksizes\n");
+               kfree (loop_dev);
+               kfree (loop_sizes);
+               return -ENOMEM;
+       }               
+
        blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
-       for (i=0; i < MAX_LOOP; i++) {
+       for (i=0; i < max_loop; i++) {
                memset(&loop_dev[i], 0, sizeof(struct loop_device));
                loop_dev[i].lo_number = i;
        }
-       memset(&loop_sizes, 0, sizeof(loop_sizes));
-       memset(&loop_blksizes, 0, sizeof(loop_blksizes));
+       memset(loop_sizes, 0, max_loop * sizeof(int));
+       memset(loop_blksizes, 0, max_loop * sizeof(int));
        blk_size[MAJOR_NR] = loop_sizes;
        blksize_size[MAJOR_NR] = loop_blksizes;
 
@@ -736,5 +772,9 @@ void cleanup_module(void)
 {
        if (unregister_blkdev(MAJOR_NR, "loop") != 0)
                printk(KERN_WARNING "loop: cannot unregister blkdev\n");
+
+       kfree (loop_dev);
+       kfree (loop_sizes);
+       kfree (loop_blksizes);
 }
 #endif
index b252e7b72c61a03386f532891bd6f4a720a7a2bd..3c5f8aa57dfceae90ca0385929c47563aaa515f7 100644 (file)
@@ -473,7 +473,8 @@ int open_for_data(struct cdrom_device_info * cdi)
                    /* give people a warning shot, now that CDO_CHECK_TYPE
                       is the default case! */
                    cdinfo(CD_OPEN, "bummer. wrong media type.\n"); 
-                   cdinfo(CD_WARNING, "pid %d is buggy!\n", (unsigned int)current->pid); 
+                   cdinfo(CD_WARNING, "pid %d must open device O_NONBLOCK!\n",
+                                       (unsigned int)current->pid); 
                    ret=-EMEDIUMTYPE;
                    goto clean_up_and_return;
                }
@@ -835,7 +836,7 @@ static int dvd_do_auth (struct cdrom_device_info *cdi, dvd_authinfo *ai)
        case DVD_HOST_SEND_CHALLENGE:
                cdinfo(CD_DO_IOCTL, "entering DVD_HOST_SEND_CHALLENGE\n"); 
                setup_send_key (&cgc, ai->hsc.agid, 1);
-               cgc.buflen = -(cgc.cmd[9] = 16);
+               cgc.buflen = cgc.cmd[9] = 16;
                buf[1] = 14;
                copy_chal (&buf[4], ai->hsc.chal);
 
@@ -848,7 +849,7 @@ static int dvd_do_auth (struct cdrom_device_info *cdi, dvd_authinfo *ai)
        case DVD_HOST_SEND_KEY2:
                cdinfo(CD_DO_IOCTL, "entering DVD_HOST_SEND_KEY2\n"); 
                setup_send_key (&cgc, ai->hsk.agid, 3);
-               cgc.buflen = -(cgc.cmd[9] = 12);
+               cgc.buflen = cgc.cmd[9] = 12;
                buf[1] = 10;
                copy_key (&buf[4], ai->hsk.key);
 
@@ -1080,13 +1081,8 @@ static int cdrom_mode_select(struct cdrom_device_info *cdi,
        
        cgc->cmd[0] = GPCMD_MODE_SELECT_10;
        cgc->cmd[1] = 0x10;             /* PF */
-
-       /* generic_packet() wants the length as seen from the drive, i.e.
-          it will transfer data _to_ us. The CD-ROM wants the absolute
-          value, however. */
-       cgc->cmd[7] = (-cgc->buflen) >> 8;
-       cgc->cmd[8] = (-cgc->buflen) & 0xff;
-
+       cgc->cmd[7] = cgc->buflen >> 8;
+       cgc->cmd[8] = cgc->buflen & 0xff;
        return cdo->generic_packet(cdi, cgc);
 }
 
@@ -1734,7 +1730,6 @@ static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
                memset(buffer, 0, 3);
 
                /* set volume */
-               cgc.buflen = -cgc.buflen;
                cgc.buffer = buffer;
                return cdrom_mode_select(cdi, &cgc);
                }
@@ -2234,12 +2229,3 @@ void cleanup_module(void)
 }
 
 #endif /* endif MODULE */
-
-
-
-/*
- * Local variables:
- * comment-column: 40
- * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -m486 -DCPU=486 -DMODULE -DMODVERSIONS -include /usr/src/linux/include/linux/modversions.h  -c -o cdrom.o cdrom.c"
- * End:
- */
index 7b4ff8b64ba86e50260699c70e0cd4d060a6ceb4..e0371a4601da6e1e20509c514a92479beb781e40 100644 (file)
@@ -69,7 +69,9 @@ if [ "$CONFIG_BUSMOUSE" != "n" ]; then
   dep_tristate 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE $CONFIG_BUSMOUSE
   dep_tristate 'Logitech busmouse support' CONFIG_LOGIBUSMOUSE $CONFIG_BUSMOUSE
   dep_tristate 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE $CONFIG_BUSMOUSE
-  dep_tristate 'Apple Desktop Bus mouse support' CONFIG_ADBMOUSE $CONFIG_BUSMOUSE
+  if [ "$CONFIG_PPC" = "y" ; then
+    dep_tristate 'Apple Desktop Bus mouse support' CONFIG_ADBMOUSE $CONFIG_BUSMOUSE
+  fi
 fi
 
 tristate 'Mouse Support (not serial and bus mice)' CONFIG_MOUSE
index 929683d44ba09771344680abb8b37eab7830dccd..c311e58cda480aea425eeb009f164c296e8da66d 100644 (file)
@@ -182,7 +182,7 @@ void cleanup_module(void)
 
 #endif /* MODULE */
 
-__initfunc(int applicom_init(void))
+int __init applicom_init(void)
 {
        int i, numisa=0;
        struct pci_dev *dev = NULL;
index 024c839a6e245b200b4007b13dcce480877c1b63..5176f28f4e9a8fdbbb97965117be94c5ee9d0949 100644 (file)
@@ -4,7 +4,7 @@
  *     istallion.c  -- stallion intelligent multiport serial driver.
  *
  *     Copyright (C) 1996-1999  Stallion Technologies (support@stallion.oz.au).
- *     Copyright (C) 1994-1996  Greg Ungerer (gerg@stallion.oz.au).
+ *     Copyright (C) 1994-1996  Greg Ungerer.
  *
  *     This code is loosely based on the Linux serial driver, written by
  *     Linus Torvalds, Theodore T'so and others.
@@ -167,7 +167,7 @@ static int  stli_nrbrds = sizeof(stli_brdconf) / sizeof(stlconf_t);
  */
 static char    *stli_drvtitle = "Stallion Intelligent Multiport Serial Driver";
 static char    *stli_drvname = "istallion";
-static char    *stli_drvversion = "5.5.1";
+static char    *stli_drvversion = "5.6.0";
 static char    *stli_serialname = "ttyE";
 static char    *stli_calloutname = "cue";
 
@@ -186,7 +186,7 @@ static int                  stli_refcount;
  *     is already swapping a shared buffer won't make things any worse.
  */
 static char                    *stli_tmpwritebuf = (char *) NULL;
-static struct semaphore                stli_tmpwritesem = MUTEX;
+static DECLARE_MUTEX(stli_tmpwritesem);
 
 #define        STLI_TXBUFSIZE          4096
 
@@ -3375,6 +3375,9 @@ static inline int stli_initports(stlibrd_t *brdp)
                portp->closing_wait = 30 * HZ;
                portp->tqhangup.routine = stli_dohangup;
                portp->tqhangup.data = portp;
+               init_waitqueue_head(&portp->open_wait);
+               init_waitqueue_head(&portp->close_wait);
+               init_waitqueue_head(&portp->raw_wait);
                portp->normaltermios = stli_deftermios;
                portp->callouttermios = stli_deftermios;
                panelport++;
@@ -4671,16 +4674,16 @@ static inline int stli_initpcibrd(int brdtype, struct pci_dev *devp)
 
 #if DEBUG
        printk("%s(%d): BAR[]=%x,%x,%x,%x\n", __FILE__, __LINE__,
-               devp->base_address[0], devp->base_address[1],
-               devp->base_address[2], devp->base_address[3]);
+               devp->resource[0].start, devp->resource[1].start,
+               devp->resource[2].start, devp->resource[3].start);
 #endif
 
 /*
  *     We have all resources from the board, so lets setup the actual
  *     board structure now.
  */
-       brdp->iobase = (devp->base_address[3] & PCI_BASE_ADDRESS_IO_MASK);
-       brdp->memaddr = (devp->base_address[2] & PCI_BASE_ADDRESS_MEM_MASK);
+       brdp->iobase = (devp->resource[3].start & PCI_BASE_ADDRESS_IO_MASK);
+       brdp->memaddr = (devp->resource[2].start & PCI_BASE_ADDRESS_MEM_MASK);
        stli_brdinit(brdp);
 
        return(0);
index f40da11d8e8df3311d9a652d41b3c1624c5dd7a9..a2097967e060acdf2e277a5524b08d91f763df88 100644 (file)
@@ -52,7 +52,6 @@
 #include <linux/malloc.h>
 #include <linux/tty.h>
 #include <linux/errno.h>
-#include <linux/sched.h>    /* to get the struct task_struct */
 #include <linux/string.h>   /* used in new tty drivers */
 #include <linux/signal.h>   /* used in new tty drivers */
 #include <linux/ioctl.h>
@@ -221,7 +220,7 @@ void cleanup_module(void)
 
 #endif /* MODULE */
 
-__initfunc(static int r3964_init(void))
+static int __init r3964_init(void)
 {
    int status;
    
index a7407d79b9ae0a79180db7c00d1a27714b06fb35..2ec8e45339cbf13847f96c0dd86e04509fa83b29 100644 (file)
 #ifdef MODVERSIONS
 #include <linux/modversions.h>
 #endif
-#include <linux/module.h>
 #else /* !NEW_MODULES */
 #ifdef MODVERSIONS
 #define MODULE
 #endif
-#include <linux/module.h>
 #endif /* NEW_MODULES */
+#include <linux/module.h>
 
 #ifdef LOCAL_HEADERS
 #include "serial_local.h"
index 3a60b522e2b1efcccad81b078383dbdd2fdee99a..b25be2cd06aa7a781680218a94ef188ba58cec4f 100644 (file)
@@ -4,7 +4,7 @@
  *     stallion.c  -- stallion multiport serial driver.
  *
  *     Copyright (C) 1996-1999  Stallion Technologies (support@stallion.oz.au).
- *     Copyright (C) 1994-1996  Greg Ungerer (gerg@stallion.oz.au).
+ *     Copyright (C) 1994-1996  Greg Ungerer.
  *
  *     This code is loosely based on the Linux serial driver, written by
  *     Linus Torvalds, Theodore T'so and others.
@@ -135,7 +135,7 @@ static int  stl_nrbrds = sizeof(stl_brdconf) / sizeof(stlconf_t);
  */
 static char    *stl_drvtitle = "Stallion Multiport Serial Driver";
 static char    *stl_drvname = "stallion";
-static char    *stl_drvversion = "5.5.1";
+static char    *stl_drvversion = "5.6.0";
 static char    *stl_serialname = "ttyE";
 static char    *stl_calloutname = "cue";
 
@@ -2294,7 +2294,7 @@ static int __init stl_mapirq(int irq, char *name)
                        break;
        }
        if (i >= stl_numintrs) {
-               if (request_irq(irq, stl_intr, SA_INTERRUPT, name, NULL) != 0) {
+               if (request_irq(irq, stl_intr, SA_SHIRQ, name, NULL) != 0) {
                        printk("STALLION: failed to register interrupt "
                                "routine for %s irq=%d\n", name, irq);
                        rc = -ENODEV;
@@ -2348,6 +2348,8 @@ static int __init stl_initports(stlbrd_t *brdp, stlpanel_t *panelp)
                portp->callouttermios = stl_deftermios;
                portp->tqueue.routine = stl_offintr;
                portp->tqueue.data = portp;
+               init_waitqueue_head(&portp->open_wait);
+               init_waitqueue_head(&portp->close_wait);
                portp->stats.brd = portp->brdnr;
                portp->stats.panel = portp->panelnr;
                portp->stats.port = portp->portnr;
@@ -2780,7 +2782,7 @@ static inline int stl_initpcibrd(int brdtype, struct pci_dev *devp)
 
 #if DEBUG
        printk("stl_initpcibrd(brdtype=%d,busnr=%x,devnr=%x)\n", brdtype,
-               dev->bus->number, dev->devfn);
+               devp->bus->number, devp->devfn);
 #endif
 
        if ((brdp = stl_allocbrd()) == (stlbrd_t *) NULL)
@@ -2798,8 +2800,8 @@ static inline int stl_initpcibrd(int brdtype, struct pci_dev *devp)
  */
 #if DEBUG
        printk("%s(%d): BAR[]=%x,%x,%x,%x IRQ=%x\n", __FILE__, __LINE__,
-               devp->base_address[0], devp->base_address[1],
-               devp->base_address[2], devp->base_address[3], devp->irq);
+               devp->resource[0].start, devp->resource[1].start,
+               devp->resource[2].start, devp->resource[3].start, devp->irq);
 #endif
 
 /*
@@ -2808,21 +2810,21 @@ static inline int stl_initpcibrd(int brdtype, struct pci_dev *devp)
  */
        switch (brdtype) {
        case BRD_ECHPCI:
-               brdp->ioaddr2 = (devp->base_address[0] &
+               brdp->ioaddr2 = (devp->resource[0].start &
                        PCI_BASE_ADDRESS_IO_MASK);
-               brdp->ioaddr1 = (devp->base_address[1] &
+               brdp->ioaddr1 = (devp->resource[1].start &
                        PCI_BASE_ADDRESS_IO_MASK);
                break;
        case BRD_ECH64PCI:
-               brdp->ioaddr2 = (devp->base_address[2] &
+               brdp->ioaddr2 = (devp->resource[2].start &
                        PCI_BASE_ADDRESS_IO_MASK);
-               brdp->ioaddr1 = (devp->base_address[1] &
+               brdp->ioaddr1 = (devp->resource[1].start &
                        PCI_BASE_ADDRESS_IO_MASK);
                break;
        case BRD_EASYIOPCI:
-               brdp->ioaddr1 = (devp->base_address[2] &
+               brdp->ioaddr1 = (devp->resource[2].start &
                        PCI_BASE_ADDRESS_IO_MASK);
-               brdp->ioaddr2 = (devp->base_address[1] &
+               brdp->ioaddr2 = (devp->resource[1].start &
                        PCI_BASE_ADDRESS_IO_MASK);
                break;
        default:
@@ -4209,6 +4211,7 @@ static void stl_cd1400rxisr(stlpanel_t *panelp, int ioaddr)
                if ((tty == (struct tty_struct *) NULL) ||
                    (tty->flip.char_buf_ptr == (char *) NULL) ||
                    ((buflen = TTY_FLIPBUF_SIZE - tty->flip.count) == 0)) {
+                       len = MIN(len, sizeof(stl_unwanted));
                        outb((RDSR + portp->uartaddr), ioaddr);
                        insb((ioaddr + EREG_DATA), &stl_unwanted[0], len);
                        portp->stats.rxlost += len;
@@ -5175,6 +5178,7 @@ static void stl_sc26198rxisr(stlport_t *portp, unsigned int iack)
                if ((tty == (struct tty_struct *) NULL) ||
                    (tty->flip.char_buf_ptr == (char *) NULL) ||
                    ((buflen = TTY_FLIPBUF_SIZE - tty->flip.count) == 0)) {
+                       len = MIN(len, sizeof(stl_unwanted));
                        outb(GRXFIFO, (ioaddr + XP_ADDR));
                        insb((ioaddr + XP_DATA), &stl_unwanted[0], len);
                        portp->stats.rxlost += len;
index 800d026cd8dd257ee00fc5cf594a29cf03bb2690..04db4e12fd687d57b07280a357e8eba839ee9071 100644 (file)
@@ -105,7 +105,7 @@ int __init i2o_pci_install(struct pci_dev *dev)
                /* Skip I/O spaces */
                if(!(dev->resource[i].flags&PCI_BASE_ADDRESS_SPACE))
                {
-                       memptr=dev->resource[i].flags;
+                       memptr=dev->resource[i].start;
                        break;
                }
        }
@@ -113,14 +113,21 @@ int __init i2o_pci_install(struct pci_dev *dev)
        if(i==6)
        {
                printk(KERN_ERR "i2o_pci: I2O controller has no memory regions defined.\n");
-               return -ENOMEM;
+               kfree(c);
+               return -EINVAL;
        }
        
        size = dev->resource[i].end-dev->resource[i].start+1;   
        /* Map the I2O controller */
        
-       printk(KERN_INFO "PCI I2O controller at 0x%08X size=%d\n", memptr, -size);
-       mem = ioremap(memptr, -size);
+       printk(KERN_INFO "PCI I2O controller at 0x%08X size=%d\n", memptr, size);
+       mem = ioremap(memptr, size);
+       if(mem==NULL)
+       {
+               printk(KERN_ERR "i2o_pci: Unable to map controller.\n");
+               kfree(c);
+               return -EINVAL;
+       }
        
        c->bus.pci.irq = -1;
 
@@ -148,6 +155,8 @@ int __init i2o_pci_install(struct pci_dev *dev)
        if(i<0)
        {
                printk(KERN_ERR "i2o: unable to install controller.\n");
+               kfree(c);
+               iounmap(mem);
                return i;
        }
 
@@ -165,7 +174,9 @@ int __init i2o_pci_install(struct pci_dev *dev)
                        core->delete(c);
 #else
                        i2o_delete_controller(c);
-#endif /* MODULE */
+#endif /* MODULE */    
+                       kfree(c);
+                       iofree(mem);
                        return -EBUSY;
                }
        }
@@ -190,8 +201,7 @@ int __init i2o_pci_scan(void)
                }
                printk(KERN_INFO "I2O controller on bus %d at %d.\n",
                        dev->bus->number, dev->devfn);
-               if(!dev->master)
-                       printk(KERN_WARNING "Controller not master enabled.\n");
+               pci_set_master(dev);
                if(i2o_pci_install(dev)==0)
                        count++;
        }
index 1f437b6acf226009af5f3c8ab23ad7b8bb2db663..7b309411b0174374b68ad95e85ad9c45273fd03f 100644 (file)
@@ -317,7 +317,7 @@ static int i2o_find_lun(struct i2o_controller *c, struct i2o_device *d, int *tar
        return 0;
 }
 
-static void i2o_scsi_init(struct i2o_controller *c, struct i2o_device *d, struct Scsi_Host *shpnt)
+void i2o_scsi_init(struct i2o_controller *c, struct i2o_device *d, struct Scsi_Host *shpnt)
 {
        struct i2o_device *unit;
        struct i2o_scsi_host *h =(struct i2o_scsi_host *)shpnt->hostdata;
index 587b763b6694bf7e76aef83960965a9927c44d4d..1ac22aa80e0f70e247f3ea424107665c74362561 100644 (file)
@@ -1275,8 +1275,8 @@ eicon_addcard(int Type, int membase, int irq, char *id)
 #define eicon_init init_module
 #endif
 
-__initfunc(int
-eicon_init(void))
+int __init
+eicon_init(void)
 {
        int card_count = 0;
        int release = 0;
@@ -1392,8 +1392,8 @@ eicon_setup(char *line)
 
        str = get_options(line, 4, ints);
 #else
-__initfunc(void
-eicon_setup(char *str, int *ints))
+void __init
+eicon_setup(char *str, int *ints)
 {
         int i, argc;
 #endif
index 2770aa65e1f045fc356cc3206583f6dc2bd2b1d7..7bcc8827c08265c7038bd9afb2134bac20081271 100644 (file)
@@ -749,8 +749,8 @@ amd7930_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        return(0);
 }
 
-__initfunc(int
-setup_amd7930(struct IsdnCard *card))
+int __init
+setup_amd7930(struct IsdnCard *card)
 {
        struct IsdnCardState *cs = card->cs;
        char tmp[64];
index 679cf9d1cd3abe54e691f38e5272afdac4e66cff..06d8b59d059ab5ac50da5112174c7506a3f47dbc 100644 (file)
@@ -326,8 +326,8 @@ Asus_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        return(0);
 }
 
-__initfunc(int
-setup_asuscom(struct IsdnCard *card))
+int __init
+setup_asuscom(struct IsdnCard *card)
 {
        int bytecnt;
        struct IsdnCardState *cs = card->cs;
index 55df36f0f73827aa06adb76a5463f78c3871ccfd..f96db367510374b26738a42d8519d3308cd23df3 100644 (file)
@@ -227,8 +227,8 @@ AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        return(0);
 }
 
-__initfunc(int
-setup_avm_a1(struct IsdnCard *card))
+int __init
+setup_avm_a1(struct IsdnCard *card)
 {
        u_char val;
        struct IsdnCardState *cs = card->cs;
index 29b630c9b2692392e986850e34cf2992f163d0d4..862829ab3bdf83f287ea398a4dd279e4982c2003 100644 (file)
@@ -262,8 +262,8 @@ AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        return 0;
 }
 
-__initfunc(int
-setup_avm_a1_pcmcia(struct IsdnCard *card))
+int __init
+setup_avm_a1_pcmcia(struct IsdnCard *card)
 {
        u_char model, vers;
        struct IsdnCardState *cs = card->cs;
index ef5ddd45fc4bf9565d48f264a24c260475fc1f48..cd293f1473050f91cca643c279494c4718afa4f7 100644 (file)
@@ -779,8 +779,8 @@ static      struct pci_dev *dev_avm __initdata = NULL;
 static  int pci_index __initdata = 0;
 #endif
 
-__initfunc(int
-setup_avm_pcipnp(struct IsdnCard *card))
+int __init
+setup_avm_pcipnp(struct IsdnCard *card)
 {
        u_int val, ver;
        struct IsdnCardState *cs = card->cs;
index 4781a822a84e24afe9c78bf84e11c8451f4f1122..57d99b43669c33e527f5bde421201552c9810e5d 100644 (file)
@@ -294,8 +294,8 @@ static struct pci_dev *dev_a4t __initdata = NULL;
 static int pci_index __initdata = 0;
 #endif
 
-__initfunc(int
-          setup_bkm_a4t(struct IsdnCard *card))
+int __init
+          setup_bkm_a4t(struct IsdnCard *card)
 {
        struct IsdnCardState *cs = card->cs;
        char tmp[64];
index 61709bfebf50b53cf74ffa2f3e11a4232a6a7ea1..e32c4544a65f3583a227acf550e4b058aa524bc3 100644 (file)
@@ -347,8 +347,8 @@ static struct pci_dev *dev_a8 __initdata = NULL;
 static int pci_index __initdata = 0;
 #endif
 
-__initfunc(int
-          setup_sct_quadro(struct IsdnCard *card))
+int __init
+          setup_sct_quadro(struct IsdnCard *card)
 {
        struct IsdnCardState *cs = card->cs;
        char tmp[64];
index ec22a3ffd40af2f026b2d3dd5059b4cda52a1083..dc0fa46a00a593ccb5268bdccce0799243d240d6 100644 (file)
@@ -571,8 +571,8 @@ HiSax_setup(char *line)
 
        str = get_options(line, MAX_ARG, ints);
 #else
-__initfunc(void
-HiSax_setup(char *str, int *ints))
+void __init
+HiSax_setup(char *str, int *ints)
 {
        int i, j, argc;
 #endif        
@@ -1442,8 +1442,8 @@ HiSax_reportcard(int cardnr)
 }
 
 
-__initfunc(int
-HiSax_init(void))
+int __init
+HiSax_init(void)
 {
        int i;
 
index 482a90695f87bd0ff7fd050dfd0b183ab99f0e07..8ec1a536c8ed0de3c1533932df4fa780a15e125b 100644 (file)
@@ -888,8 +888,8 @@ static      struct pci_dev *dev_diva201 __initdata = NULL;
 static  int pci_index __initdata = 0;
 #endif
 
-__initfunc(int
-setup_diva(struct IsdnCard *card))
+int __init
+setup_diva(struct IsdnCard *card)
 {
        int bytecnt;
        u_char val;
index ce83fc8590862224b3cdbbd49e2438c007985d62..ef64a4702dff4a4ceb27a2ef52c991314e2479cb 100644 (file)
@@ -690,8 +690,8 @@ setup_gazelpci(struct IsdnCardState *cs)
        return (0);
 }
 
-__initfunc(int
-          setup_gazel(struct IsdnCard *card))
+int __init
+          setup_gazel(struct IsdnCard *card)
 {
        struct IsdnCardState *cs = card->cs;
        char tmp[64];
index cbb64fbab98f6e3bba7000915cd9783eca1a6d36..266916c39af4d4bab5db7a72c39841a043d63ab0 100644 (file)
@@ -1172,8 +1172,8 @@ hfc_dbusy_timer(struct IsdnCardState *cs)
 #endif
 }
 
-__initfunc(unsigned int
-*init_send_hfcd(int cnt))
+unsigned int * __init
+init_send_hfcd(int cnt)
 {
        int i, *send;
 
@@ -1187,8 +1187,8 @@ __initfunc(unsigned int
        return(send);
 }
 
-__initfunc(void
-init2bds0(struct IsdnCardState *cs))
+void __init
+init2bds0(struct IsdnCardState *cs)
 {
        cs->setstack_d = setstack_hfcd;
        cs->dbusytimer.function = (void *) hfc_dbusy_timer;
index 86515e17d273fc619f6eafd812f64ed541be3e35..71767c888d58c1deb3ca184731cf2ef98223f27a 100644 (file)
@@ -559,8 +559,8 @@ setstack_hfc(struct PStack *st, struct BCState *bcs)
        return (0);
 }
 
-__initfunc(void
-init_send(struct BCState *bcs))
+void __init
+init_send(struct BCState *bcs)
 {
        int i;
 
@@ -573,8 +573,8 @@ init_send(struct BCState *bcs))
                bcs->hw.hfc.send[i] = 0x1fff;
 }
 
-__initfunc(void
-inithfc(struct IsdnCardState *cs))
+void __init
+inithfc(struct IsdnCardState *cs)
 {
        init_send(&cs->bcs[0]);
        init_send(&cs->bcs[1]);
index 72e7309b906e1f8c9ee4b84be1d6dee9493b4894..9d8968e988dc6a95ff22effcbd943e95cc846270 100644 (file)
@@ -1513,8 +1513,8 @@ hfcpci_bh(struct IsdnCardState *cs)
 /*************************************/
 /* Alloc memory send data for queues */
 /*************************************/
-__initfunc(unsigned int
-          *init_send_hfcpci(int cnt))
+unsigned int * __init 
+       init_send_hfcpci(int cnt)
 {
        int i, *send;
 
@@ -1531,8 +1531,8 @@ __initfunc(unsigned int
 /********************************/
 /* called for card init message */
 /********************************/
-__initfunc(void
-          inithfcpci(struct IsdnCardState *cs))
+void __init
+       inithfcpci(struct IsdnCardState *cs)
 {
        cs->setstack_d = setstack_hfcpci;
        cs->dbusytimer.function = (void *) hfcpci_dbusy_timer;
@@ -1604,8 +1604,8 @@ static int pci_index __initdata = 0;
 
 #endif                         /* CONFIG_PCI */
 
-__initfunc(int
-          setup_hfcpci(struct IsdnCard *card))
+int __init
+       setup_hfcpci(struct IsdnCard *card)
 {
        struct IsdnCardState *cs = card->cs;
        char tmp[64];
index edd3836431cbd5baa3dfbdde310941e7f29f1cf6..05735e150e5f4123df5eabe5e956c89ec15f7af0 100644 (file)
@@ -148,8 +148,8 @@ hfcs_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        return(0);
 }
 
-__initfunc(int
-setup_hfcs(struct IsdnCard *card))
+int __init
+setup_hfcs(struct IsdnCard *card)
 {
        struct IsdnCardState *cs = card->cs;
        char tmp[64];
index b2859bce73f0647c6410b10a52d828b9325d4164..0fdf65a409ea6294846b741b477f93001b9755aa 100644 (file)
@@ -1007,6 +1007,10 @@ struct IsdnCardState {
 #define __initdata
 #endif
 
+#ifndef __init
+#define __init
+#endif
+
 #define HISAX_INITFUNC(__arginit) __initfunc(__arginit)
 #define HISAX_INITDATA __initdata
 
index 22e54fd8e92aef0abd5880f2293292d56c11bf05..dd713921a6c04af6b3465cd1b1532cbbb2684cda 100644 (file)
@@ -206,8 +206,8 @@ isurf_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic) {
        return(isar_auxcmd(cs, ic));
 }
 
-__initfunc(int
-setup_isurf(struct IsdnCard *card))
+int __init
+setup_isurf(struct IsdnCard *card)
 {
        int ver;
        struct IsdnCardState *cs = card->cs;
index cb94d5bb392c3373434634886960c1a33df2ec26..389d043a342be409bae118179c71c3fbfcce584e 100644 (file)
@@ -282,8 +282,8 @@ ix1_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 }
 
 
-__initfunc(int
-setup_ix1micro(struct IsdnCard *card))
+int __init
+setup_ix1micro(struct IsdnCard *card)
 {
        struct IsdnCardState *cs = card->cs;
        char tmp[64];
index be65f1101ca09adda2addcc7cd08fdd0a76136b1..fa85bbd27a7846a469f265ce457d4391e1f7151b 100644 (file)
@@ -224,8 +224,8 @@ mic_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        return(0);
 }
 
-__initfunc(int
-setup_mic(struct IsdnCard *card))
+int __init
+setup_mic(struct IsdnCard *card)
 {
        int bytecnt;
        struct IsdnCardState *cs = card->cs;
index 7043959e9db6a41579af65d4de0f5d292ae5ebeb..d88442e377d3e17ec44b5fc0b21f59c98c2c4527 100644 (file)
@@ -889,8 +889,8 @@ setstack_tiger(struct PStack *st, struct BCState *bcs)
 }
 
  
-__initfunc(void
-inittiger(struct IsdnCardState *cs))
+void __init
+inittiger(struct IsdnCardState *cs)
 {
        if (!(cs->bcs[0].hw.tiger.send = kmalloc(NETJET_DMA_TXSIZE * sizeof(unsigned int),
                GFP_KERNEL | GFP_DMA))) {
@@ -1080,8 +1080,8 @@ static    struct pci_dev *dev_netjet __initdata = NULL;
 static  int pci_index __initdata = 0;
 #endif
 
-__initfunc(int
-setup_netjet(struct IsdnCard *card))
+int __init
+setup_netjet(struct IsdnCard *card)
 {
        int bytecnt;
        struct IsdnCardState *cs = card->cs;
index d83287d23287e880bf331689572aa1c98d299fae..7574a8e8fb64a5cfc24dc57e5a1120ad27b85263 100644 (file)
@@ -265,8 +265,8 @@ static      struct pci_dev *niccy_dev __initdata = NULL;
 static  int pci_index __initdata = 0;
 #endif
 
-__initfunc(int
-setup_niccy(struct IsdnCard *card))
+int __init
+setup_niccy(struct IsdnCard *card)
 {
        struct IsdnCardState *cs = card->cs;
        char tmp[64];
index 51bc116584160cc5563b262f7be7249bc2aee536..d8dfb2ee3f0606fa60ca47d37dab6b97942c3de8 100644 (file)
@@ -212,8 +212,8 @@ S0Box_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        return(0);
 }
 
-__initfunc(int
-setup_s0box(struct IsdnCard *card))
+int __init
+setup_s0box(struct IsdnCard *card)
 {
        struct IsdnCardState *cs = card->cs;
        char tmp[64];
index b132afc2c51eda8c9f277180cad1153174e5d595..0d524faa869bc35d388d887dac9a139f765807c8 100644 (file)
@@ -265,8 +265,8 @@ saphir_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 }
 
 
-__initfunc(int
-setup_saphir(struct IsdnCard *card))
+int __init
+setup_saphir(struct IsdnCard *card)
 {
        struct IsdnCardState *cs = card->cs;
        char tmp[64];
index e1e1b552d5041fd24556bea9a7f75a5584341db9..2640555b2d374f49e0ee91cc10b819320f0ae74f 100644 (file)
@@ -549,8 +549,8 @@ static  int pci_index __initdata = 0;
 #endif
 #endif
 
-__initfunc(int
-setup_sedlbauer(struct IsdnCard *card))
+int __init
+setup_sedlbauer(struct IsdnCard *card)
 {
        int bytecnt, ver, val;
        struct IsdnCardState *cs = card->cs;
index 0d062dadaf3684dfd24a038165abf74143b55c5e..29fae02f7c39d5afca279aee25f32df405d1aa0b 100644 (file)
@@ -208,8 +208,8 @@ Sportster_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        return(0);
 }
 
-__initfunc(int
-get_io_range(struct IsdnCardState *cs))
+int __init
+get_io_range(struct IsdnCardState *cs)
 {
        int i, j, adr;
        
@@ -234,8 +234,8 @@ get_io_range(struct IsdnCardState *cs))
        }
 }
 
-__initfunc(int
-setup_sportster(struct IsdnCard *card))
+int __init
+setup_sportster(struct IsdnCard *card)
 {
        struct IsdnCardState *cs = card->cs;
        char tmp[64];
index 05a74bdf7f97afceceaf29e827ff28fbad736319..430ea2768f99eb757dd8d7c54ea062b302e9f370 100644 (file)
@@ -289,8 +289,8 @@ TeleInt_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        return(0);
 }
 
-__initfunc(int
-setup_TeleInt(struct IsdnCard *card))
+int __init
+setup_TeleInt(struct IsdnCard *card)
 {
        struct IsdnCardState *cs = card->cs;
        char tmp[64];
index 866e8dac5effc29f1b5f4d2f02aaa885b0d5f290..4046c4357d25ee8a75c670eaff958a729b6d0a89 100644 (file)
@@ -295,8 +295,8 @@ Teles_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        return(0);
 }
 
-__initfunc(int
-setup_teles0(struct IsdnCard *card))
+int __init
+setup_teles0(struct IsdnCard *card)
 {
        u_char val;
        struct IsdnCardState *cs = card->cs;
index 0db245abcfc860b28ef83761d8eade039cfd1e8b..3210a6af68a1adea9b291c84be9d369e1e0ab5d4 100644 (file)
@@ -321,8 +321,8 @@ Teles_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        return(0);
 }
 
-__initfunc(int
-setup_teles3(struct IsdnCard *card))
+int __init
+setup_teles3(struct IsdnCard *card)
 {
        u_char val;
        struct IsdnCardState *cs = card->cs;
index dd9e5fb4a2fe965472394e84babe84a94e25166d..9ffe99918bb8cd9b7b42bdac10c63f8eae971c5d 100644 (file)
@@ -310,8 +310,8 @@ static      struct pci_dev *dev_tel __initdata = NULL;
 static         int pci_index __initdata = 0;
 #endif
 
-__initfunc(int
-setup_telespci(struct IsdnCard *card))
+int __init
+setup_telespci(struct IsdnCard *card)
 {
        struct IsdnCardState *cs = card->cs;
        char tmp[64];
index 19efa3ee23add93bd030ecbd581f2a973279e915..fbfd71d93369180555e075c4daba8c9890fc6db1 100644 (file)
@@ -549,7 +549,7 @@ int __init dfx_probe(struct net_device *dev)
 
                                /* Get I/O base address from PCI Configuration Space */
 
-                               port = pdev->resource[1].start
+                               port = pdev->resource[1].start;
 
                                /* Verify port address range is not already being used */
 
index 43eec1f1979ef7482cfd01fecb11e7c3b21d85dd..e04660f7a702af21e430539dbf5e56068386bed7 100644 (file)
@@ -131,7 +131,6 @@ extern __inline__ void dev_init_buffers(struct net_device *dev)
 #else
 #define __init
 #define __initdata
-#define __initfunc(x) x
 #endif
 
 /* --------------------------------------------------------------------- */
@@ -1201,7 +1200,7 @@ static int yam_probe(struct net_device *dev)
 
 /* --------------------------------------------------------------------- */
 
-__initfunc(int yam_init(struct net_device *dev))
+int __init yam_init(struct net_device *dev)
 {
        int i;
 
@@ -1267,7 +1266,7 @@ MODULE_DESCRIPTION("Yam amateur radio modem driver");
 
 #endif
 
-__initfunc(int init_module(void))
+int init_module(void)
 {
        int ret = yam_init(NULL);
 
index 0c4cd584676a1876b759f14c8a8adf72cdc0a3c2..552061da11d0137da73145b09696726142c89c0b 100644 (file)
@@ -20,7 +20,7 @@
  * ==FILEVERSION 990806==
  */
 
-/* $Id$ */
+/* $Id: ppp_async.c,v 1.3 1999/09/02 05:30:10 paulus Exp $ */
 
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -895,8 +895,7 @@ ppp_async_input(struct asyncppp *ap, const unsigned char *buf,
                        /* stuff the chars in the skb */
                        skb = ap->rpkt;
                        if (skb == 0) {
-                               skb = alloc_skb(ap->mru + PPP_HDRLEN + 2,
-                                               GFP_ATOMIC);
+                               skb = dev_alloc_skb(ap->mru + PPP_HDRLEN + 2);
                                if (skb == 0)
                                        goto nomem;
                                /* Try to get the payload 4-byte aligned */
index 3190821ddf5ea25e46691f4817bcb40c528ac76d..0dcee1ba1b6704840ec2080d4bf707d5db5e09ca 100644 (file)
@@ -22,7 +22,7 @@
  * ==FILEVERSION 990806==
  */
 
-/* $Id$ */
+/* $Id: ppp_generic.c,v 1.3 1999/09/02 05:30:12 paulus Exp $ */
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -94,7 +94,7 @@ struct ppp {
        void            *rc_state;      /* its internal state */
        unsigned long   last_xmit;      /* jiffies when last pkt sent */
        unsigned long   last_recv;      /* jiffies when last pkt rcvd */
-       struct net_device       dev;            /* network interface device */
+       struct net_device *dev;         /* network interface device */
        struct net_device_stats stats;  /* statistics */
 };
 
@@ -144,6 +144,7 @@ static void ppp_ccp_closed(struct ppp *ppp);
 static struct compressor *find_compressor(int type);
 static void ppp_get_stats(struct ppp *ppp, struct ppp_stats *st);
 static struct ppp *ppp_create_unit(int unit, int *retp);
+static void ppp_release_unit(struct ppp *ppp);
 static struct ppp *ppp_find_unit(int unit);
 
 /* Translates a PPP protocol number to a NP index (NP == network protocol) */
@@ -267,49 +268,11 @@ static int ppp_open(struct inode *inode, struct file *file)
 static int ppp_release(struct inode *inode, struct file *file)
 {
        struct ppp *ppp = (struct ppp *) file->private_data;
-       struct list_head *list, *next;
-       int ref;
-
-       if (ppp == 0)
-               goto out;
-       file->private_data = 0;
-       spin_lock(&all_ppp_lock);
-       ref = --ppp->refcnt;
-       if (ref == 0)
-               list_del(&ppp->list);
-       spin_unlock(&all_ppp_lock);
-       if (ref != 0)
-               goto out;
 
-       /* Last fd open to this ppp unit is being closed -
-          mark the interface down, free the ppp unit */
-       rtnl_lock();
-       dev_close(&ppp->dev);
-       rtnl_unlock();
-       for (list = ppp->channels.next; list != &ppp->channels; list = next) {
-               /* forcibly detach this channel */
-               struct channel *chan;
-               chan = list_entry(list, struct channel, list);
-               chan->chan->ppp = 0;
-               next = list->next;
-               kfree(chan);
+       if (ppp != 0) {
+               file->private_data = 0;
+               ppp_release_unit(ppp);
        }
-
-       /* Free up resources. */
-       ppp_ccp_closed(ppp);
-       lock_xmit_path(ppp);
-       lock_recv_path(ppp);
-       if (ppp->vj) {
-               slhc_free(ppp->vj);
-               ppp->vj = 0;
-       }
-       free_skbs(&ppp->xq);
-       free_skbs(&ppp->rq);
-       free_skbs(&ppp->recv_pending);
-       unregister_netdev(&ppp->dev);
-       kfree(ppp);
-
- out:
        MOD_DEC_USE_COUNT;
        return 0;
 }
@@ -453,6 +416,12 @@ static int ppp_ioctl(struct inode *inode, struct file *file,
                return -ENXIO;
        err = -EFAULT;
        switch (cmd) {
+       case PPPIOCDETACH:
+               file->private_data = 0;
+               ppp_release_unit(ppp);
+               err = 0;
+               break;
+
        case PPPIOCSMRU:
                if (get_user(val, (int *) arg))
                        break;
@@ -832,7 +801,7 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb)
        /* try to do packet compression */
        if ((ppp->xstate & SC_COMP_RUN) && ppp->xc_state != 0
            && proto != PPP_LCP && proto != PPP_CCP) {
-               new_skb = alloc_skb(ppp->dev.mtu + PPP_HDRLEN, GFP_ATOMIC);
+               new_skb = alloc_skb(ppp->dev->mtu + PPP_HDRLEN, GFP_ATOMIC);
                if (new_skb == 0) {
                        printk(KERN_ERR "PPP: no memory (comp pkt)\n");
                        goto drop;
@@ -841,7 +810,7 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb)
                /* compressor still expects A/C bytes in hdr */
                len = ppp->xcomp->compress(ppp->xc_state, skb->data - 2,
                                           new_skb->data, skb->len + 2,
-                                          ppp->dev.mtu + PPP_HDRLEN);
+                                          ppp->dev->mtu + PPP_HDRLEN);
                if (len > 0 && (ppp->flags & SC_CCP_UP)) {
                        kfree_skb(skb);
                        skb = new_skb;
@@ -853,6 +822,10 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb)
                }
        }
 
+       /* for data packets, record the time */
+       if (proto < 0x8000)
+               ppp->last_xmit = jiffies;
+
        /*
         * If we are waiting for traffic (demand dialling),
         * queue it up for pppd to receive.
@@ -994,7 +967,7 @@ ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb)
                        goto err;
                if (skb_tailroom(skb) < 124) {
                        /* copy to a new sk_buff with more tailroom */
-                       ns = alloc_skb(skb->len + 128, GFP_ATOMIC);
+                       ns = dev_alloc_skb(skb->len + 128);
                        if (ns == 0) {
                                printk(KERN_ERR"PPP: no memory (VJ decomp)\n");
                                goto err;
@@ -1051,12 +1024,12 @@ ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb)
        } else {
                /* network protocol frame - give it to the kernel */
                ppp->last_recv = jiffies;
-               if ((ppp->dev.flags & IFF_UP) == 0
+               if ((ppp->dev->flags & IFF_UP) == 0
                    || ppp->npmode[npi] != NPMODE_PASS) {
                        kfree_skb(skb);
                } else {
                        skb_pull(skb, 2);       /* chop off protocol */
-                       skb->dev = &ppp->dev;
+                       skb->dev = ppp->dev;
                        skb->protocol = htons(npindex_to_ethertype[npi]);
                        skb->mac.raw = skb->data;
                        netif_rx(skb);
@@ -1079,7 +1052,7 @@ ppp_decompress_frame(struct ppp *ppp, struct sk_buff *skb)
        int len;
 
        if (proto == PPP_COMP) {
-               ns = alloc_skb(ppp->mru + PPP_HDRLEN, GFP_ATOMIC);
+               ns = dev_alloc_skb(ppp->mru + PPP_HDRLEN);
                if (ns == 0) {
                        printk(KERN_ERR "ppp_receive: no memory\n");
                        goto err;
@@ -1189,7 +1162,7 @@ ppp_output_wakeup(struct ppp_channel *chan)
        if (trylock_xmit_path(ppp))
                ppp_xmit_unlock(ppp);
        if (ppp->xmit_pending == 0) {
-               ppp->dev.tbusy = 0;
+               ppp->dev->tbusy = 0;
                mark_bh(NET_BH);
        }
 }
@@ -1476,6 +1449,7 @@ static struct ppp *
 ppp_create_unit(int unit, int *retp)
 {
        struct ppp *ppp;
+       struct net_device *dev;
        struct list_head *list;
        int last_unit = -1;
        int ret = -EEXIST;
@@ -1501,6 +1475,12 @@ ppp_create_unit(int unit, int *retp)
        if (ppp == 0)
                goto out;
        memset(ppp, 0, sizeof(struct ppp));
+       dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
+       if (dev == 0) {
+               kfree(ppp);
+               goto out;
+       }
+       memset(dev, 0, sizeof(struct net_device));
 
        ppp->index = unit;
        sprintf(ppp->name, "ppp%d", unit);
@@ -1514,13 +1494,18 @@ ppp_create_unit(int unit, int *retp)
        INIT_LIST_HEAD(&ppp->channels);
        skb_queue_head_init(&ppp->recv_pending);
 
-       ppp->dev.init = ppp_net_init;
-       ppp->dev.name = ppp->name;
-       ppp->dev.priv = ppp;
+       ppp->dev = dev;
+       dev->init = ppp_net_init;
+       dev->name = ppp->name;
+       dev->priv = ppp;
+       dev->new_style = 1;
 
-       ret = register_netdev(&ppp->dev);
+       rtnl_lock();
+       ret = register_netdevice(dev);
+       rtnl_unlock();
        if (ret != 0) {
                printk(KERN_ERR "PPP: couldn't register device (%d)\n", ret);
+               kfree(dev);
                kfree(ppp);
                goto out;
        }
@@ -1534,6 +1519,59 @@ ppp_create_unit(int unit, int *retp)
        return ppp;
 }
 
+/*
+ * Remove a reference to a ppp unit, and destroy it if
+ * the reference count goes to 0.
+ */
+static void ppp_release_unit(struct ppp *ppp)
+{
+       struct list_head *list, *next;
+       int ref;
+
+       spin_lock(&all_ppp_lock);
+       ref = --ppp->refcnt;
+       if (ref == 0)
+               list_del(&ppp->list);
+       spin_unlock(&all_ppp_lock);
+       if (ref != 0)
+               return;
+
+       /* Last fd open to this ppp unit is being closed or detached:
+          mark the interface down, free the ppp unit */
+       if (ppp->dev) {
+               rtnl_lock();
+               dev_close(ppp->dev);
+               rtnl_unlock();
+       }
+       for (list = ppp->channels.next; list != &ppp->channels; list = next) {
+               /* forcibly detach this channel */
+               struct channel *chan;
+               chan = list_entry(list, struct channel, list);
+               chan->chan->ppp = 0;
+               next = list->next;
+               kfree(chan);
+       }
+
+       /* Free up resources. */
+       ppp_ccp_closed(ppp);
+       lock_xmit_path(ppp);
+       lock_recv_path(ppp);
+       if (ppp->vj) {
+               slhc_free(ppp->vj);
+               ppp->vj = 0;
+       }
+       free_skbs(&ppp->xq);
+       free_skbs(&ppp->rq);
+       free_skbs(&ppp->recv_pending);
+       if (ppp->dev) {
+               rtnl_lock();
+               unregister_netdevice(ppp->dev);
+               ppp->dev = 0;
+               rtnl_unlock();
+       }
+       kfree(ppp);
+}
+
 /*
  * Locate an existing ppp unit.
  * The caller should have locked the all_ppp_lock.
@@ -1568,7 +1606,7 @@ void
 cleanup_module(void)
 {
        /* should never happen */
-       if (all_ppp_units.next != &all_ppp_units)
+       if (!list_empty(&all_ppp_units))
                printk(KERN_ERR "PPP: removing module but units remain!\n");
        if (unregister_chrdev(PPP_MAJOR, "ppp") != 0)
                printk(KERN_ERR "PPP: failed to unregister PPP device\n");
index 991bbda9809b4fc0fdd4f90e3db02a3c39e80009..45197e4c35dfb8daef680f0caa6666d39ef1200c 100644 (file)
@@ -25,6 +25,6 @@ ifdef CONFIG_PROC_FS
 L_OBJS   += proc.o
 endif
 
-L_OBJS   += compat.o quirks.o names.o
+L_OBJS   += compat.o quirks.o names.o syscall.o setup.o
 
 include $(TOPDIR)/Rules.make
index c400ad10b83e0bfb5e5ed7296ce82b180c1595fe..dbd5a8e310646f39d836d5ff63e3f60694b26228 100644 (file)
@@ -295,7 +295,7 @@ void __init pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
        pci_write_config_word(dev, PCI_COMMAND, cmd);
 }
 
-static void __init pci_read_bridge_bases(struct pci_dev *dev, struct pci_bus *child)
+void __init pci_read_bridge_bases(struct pci_dev *dev, struct pci_bus *child)
 {
        u8 io_base_lo, io_limit_lo;
        u16 mem_base_lo, mem_limit_lo, io_base_hi, io_limit_hi;
@@ -513,7 +513,6 @@ static unsigned int __init pci_do_scan_bus(struct pci_bus *bus)
                        child->primary = bus->secondary;
                        child->subordinate = 0xff;
                        sprintf(child->name, "PCI Bus #%02x", child->number);
-                       pci_read_bridge_bases(dev, child);
                        /*
                         * Clear all status bits and turn off memory,
                         * I/O and master enables.
index 2aefa5dfb6e51d3bd96496542836abe9da720aa9..5b1c8e82972850b87bec674102cb457a1e08510c 100644 (file)
@@ -67,13 +67,8 @@ static void __init quirk_s3_64M(struct pci_dev *dev)
        struct resource *r = &dev->resource[0];
 
        if ((r->start & 0x3ffffff) || r->end != r->start + 0x3ffffff) {
-               printk("PCI: Re-allocating buggy S3 card at %s: ", dev->name);
                r->start = 0;
                r->end = 0x3ffffff;
-               if (pcibios_assign_resource(dev, 0))
-                       printk("FAILED\n");
-               else
-                       printk("moved to %08lx\n", r->start);
        }
 }
 
@@ -90,8 +85,8 @@ static struct pci_fixup pci_fixups[] __initdata = {
         * quantity.
         */
        { PCI_FIXUP_FINAL,      PCI_VENDOR_ID_VIA,      PCI_DEVICE_ID_VIA_82C586_0,     quirk_isa_dma_hangs },
-       { PCI_FIXUP_FINAL,      PCI_VENDOR_ID_S3,       PCI_DEVICE_ID_S3_868,           quirk_s3_64M },
-       { PCI_FIXUP_FINAL,      PCI_VENDOR_ID_S3,       PCI_DEVICE_ID_S3_968,           quirk_s3_64M },
+       { PCI_FIXUP_HEADER,     PCI_VENDOR_ID_S3,       PCI_DEVICE_ID_S3_868,           quirk_s3_64M },
+       { PCI_FIXUP_HEADER,     PCI_VENDOR_ID_S3,       PCI_DEVICE_ID_S3_968,           quirk_s3_64M },
        { 0 }
 };
 
diff --git a/drivers/pci/setup.c b/drivers/pci/setup.c
new file mode 100644 (file)
index 0000000..2038623
--- /dev/null
@@ -0,0 +1,324 @@
+/*
+ *     drivers/pci/setup.c
+ *
+ * Extruded from code written by
+ *      Dave Rusling (david.rusling@reo.mts.dec.com)
+ *      David Mosberger (davidm@cs.arizona.edu)
+ *     David Miller (davem@redhat.com)
+ *
+ * Support routines for initializing a PCI subsystem.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+
+#include <asm/cache.h>
+#include <asm/pci.h>
+
+
+#define DEBUG_CONFIG 0
+#if DEBUG_CONFIG
+# define DBGC(args)     printk args
+#else
+# define DBGC(args)
+#endif
+
+
+int __init
+pci_claim_resource(struct pci_dev *dev, int resource)
+{
+        struct resource *res = &dev->resource[resource];
+       struct resource *root = pci_find_parent_resource(dev, res);
+       int err;
+
+       err = -EINVAL;
+       if (root != NULL) {
+               /* If `dev' is on a secondary pci bus, `root' may not be
+                  at the origin.  In that case, adjust the resource into
+                  range.  */
+               res->start += root->start;
+               res->end += root->start;
+
+               err = request_resource(root, res);
+       }
+       if (err) {
+               printk(KERN_ERR "PCI: Address space collision on region %d "
+                      "of device %s\n", resource, dev->name);
+       }
+
+       return err;
+}
+
+static void
+pdev_assign_unassigned_resources(struct pci_dev *dev, u32 min_io, u32 min_mem)
+{
+       u32 reg;
+       u16 cmd;
+       int i;
+
+       DBGC(("PCI assign unassigned: (%s)\n", dev->name));
+
+       pci_read_config_word(dev, PCI_COMMAND, &cmd);
+
+       for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+               struct resource *root, *res;
+               unsigned long size, min;
+
+               res = &dev->resource[i];
+
+               if (res->flags & IORESOURCE_IO)
+                       cmd |= PCI_COMMAND_IO;
+               else if (res->flags & IORESOURCE_MEM)
+                       cmd |= PCI_COMMAND_MEMORY;
+
+               /* If it is already assigned or the resource does
+                  not exist, there is nothing to do.  */
+               if (res->parent != NULL || res->flags == 0)
+                       continue;
+
+               /* Determine the root we allocate from.  */
+               root = pci_find_parent_resource(dev, res);
+               if (root == NULL)
+                       continue;
+
+               min = (res->flags & IORESOURCE_IO ? min_io : min_mem);
+               min += root->start;
+               size = res->end - res->start + 1;
+
+               DBGC(("  for root[%lx:%lx] min[%lx] size[%lx]\n",
+                     root->start, root->end, min, size));
+
+               if (allocate_resource(root, res, size, min, -1, size) < 0) {
+                       printk(KERN_ERR
+                              "PCI: Failed to allocate resource %d for %s\n",
+                              i, dev->name);
+                       continue;
+               }
+
+               DBGC(("  got res[%lx:%lx] for resource %d\n",
+                     res->start, res->end, i));
+
+               /* Update PCI config space.  */
+               pcibios_update_resource(dev, root, res, i);
+       }
+
+       /* Special case, disable the ROM.  Several devices act funny
+          (ie. do not respond to memory space writes) when it is left
+          enabled.  A good example are QlogicISP adapters.  */
+
+       pci_read_config_dword(dev, PCI_ROM_ADDRESS, &reg);
+       reg &= ~PCI_ROM_ADDRESS_ENABLE;
+       pci_write_config_dword(dev, PCI_ROM_ADDRESS, reg);
+
+       /* All of these (may) have I/O scattered all around and may not
+          use I/O base address registers at all.  So we just have to
+          always enable IO to these devices.  */
+       if ((dev->class >> 8) == PCI_CLASS_NOT_DEFINED
+           || (dev->class >> 8) == PCI_CLASS_NOT_DEFINED_VGA
+           || (dev->class >> 8) == PCI_CLASS_STORAGE_IDE
+           || (dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
+               cmd |= PCI_COMMAND_IO;
+       }
+
+       /* ??? Always turn on bus mastering.  If the device doesn't support
+          it, the bit will go into the bucket. */
+       cmd |= PCI_COMMAND_MASTER;
+
+       /* Enable the appropriate bits in the PCI command register.  */
+       pci_write_config_word(dev, PCI_COMMAND, cmd);
+
+       DBGC(("  cmd reg 0x%x\n", cmd));
+
+       /* If this is a PCI bridge, set the cache line correctly.  */
+       if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
+               pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
+                                     (L1_CACHE_BYTES / sizeof(u32)));
+       }
+}
+
+void __init
+pci_assign_unassigned_resources(u32 min_io, u32 min_mem)
+{
+       struct pci_dev *dev;
+       for (dev = pci_devices; dev; dev = dev->next)
+               pdev_assign_unassigned_resources(dev, min_io, min_mem);
+}
+
+struct pbus_set_ranges_data
+{
+       int found_vga;
+       unsigned int io_start, io_end;
+       unsigned int mem_start, mem_end;
+};
+
+#define ROUND_UP(x, a)         (((x) + (a) - 1) & ~((a) - 1))
+#define ROUND_DOWN(x, a)       ((x) & ~((a) - 1))
+
+static void __init
+pbus_set_ranges(struct pci_bus *bus, struct pbus_set_ranges_data *outer)
+{
+       struct pbus_set_ranges_data inner;
+       struct pci_bus *child;
+       struct pci_dev *dev;
+
+       inner.found_vga = 0;
+       inner.mem_start = inner.io_start = ~0;
+       inner.mem_end = inner.io_end = 0;
+
+       /* Collect information about how our direct children are layed out. */
+       for (dev = bus->devices; dev; dev = dev->sibling) {
+               int i;
+               for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+                       struct resource *res = &dev->resource[i];
+                       if (res->flags & IORESOURCE_IO) {
+                               if (res->start < inner.io_start)
+                                       inner.io_start = res->start;
+                               if (res->end > inner.io_end)
+                                       inner.io_end = res->end;
+                       } else if (res->flags & IORESOURCE_MEM) {
+                               if (res->start < inner.mem_start)
+                                       inner.mem_start = res->start;
+                               if (res->end > inner.mem_end)
+                                       inner.mem_end = res->end;
+                       }
+               }
+                if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA)
+                        inner.found_vga = 1;
+       }
+
+       /* And for all of the sub-busses.  */
+       for (child = bus->children; child; child = child->next)
+               pbus_set_ranges(child, &inner);
+
+       /* Align the values.  */
+       inner.io_start = ROUND_DOWN(inner.io_start, 4*1024);
+       inner.io_end = ROUND_UP(inner.io_end, 4*1024);
+
+       inner.mem_start = ROUND_DOWN(inner.mem_start, 1*1024*1024);
+       inner.mem_end = ROUND_UP(inner.mem_end, 1*1024*1024);
+
+       /* Configure the bridge, if possible.  */
+       if (bus->self) {
+               struct pci_dev *bridge = bus->self;
+               u32 l;
+
+                /* Set up the top and bottom of the PCI I/O segment
+                   for this bus.  */
+                pci_read_config_dword(bridge, PCI_IO_BASE, &l);
+                l &= 0xffff0000;
+                l |= (inner.io_start >> 8) & 0x00f0;
+               l |= (inner.io_end - 1) & 0xf000;
+                pci_write_config_dword(bridge, PCI_IO_BASE, l);
+
+                /*
+                 * Clear out the upper 16 bits of IO base/limit.
+                 * Clear out the upper 32 bits of PREF base/limit.
+                 */
+                pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, 0);
+                pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, 0);
+                pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0);
+
+                /* Set up the top and bottom of the PCI Memory segment
+                   for this bus.  */
+                l = (inner.mem_start & 0xfff00000) >> 16;
+               l |= (inner.mem_end - 1) & 0xfff00000;
+                pci_write_config_dword(bridge, PCI_MEMORY_BASE, l);
+
+                /*
+                 * Turn off downstream PF memory address range, unless
+                 * there is a VGA behind this bridge, in which case, we
+                 * enable the PREFETCH range to include BIOS ROM at C0000.
+                 *
+                 * NOTE: this is a bit of a hack, done with PREFETCH for
+                 * simplicity, rather than having to add it into the above
+                 * non-PREFETCH range, which could then be bigger than we want.
+                 * We might assume that we could relocate the BIOS ROM, but
+                 * that would depend on having it found by those who need it
+                 * (the DEC BIOS emulator would find it, but I do not know
+                 * about the Xservers). So, we do it this way for now... ;-)
+                 */
+                l = (inner.found_vga) ? 0 : 0x0000ffff;
+                pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l);
+
+                /*
+                 * Tell bridge that there is an ISA bus in the system,
+                 * and (possibly) a VGA as well.
+                 */
+                l = (inner.found_vga) ? 0x0c : 0x04;
+                pci_write_config_byte(bridge, PCI_BRIDGE_CONTROL, l);
+
+                /*
+                 * Clear status bits,
+                 * turn on I/O    enable (for downstream I/O),
+                 * turn on memory enable (for downstream memory),
+                 * turn on master enable (for upstream memory and I/O).
+                 */
+                pci_write_config_dword(bridge, PCI_COMMAND, 0xffff0007);
+       }
+
+       if (outer) {
+               outer->found_vga |= inner.found_vga;
+               if (inner.io_start < outer->io_start)
+                       outer->io_start = inner.io_start;
+               if (inner.io_end > outer->io_end)
+                       outer->io_end = inner.io_end;
+               if (inner.mem_start < outer->mem_start)
+                       outer->mem_start = inner.mem_start;
+               if (inner.mem_end > outer->mem_end)
+                       outer->mem_end = inner.mem_end;
+       }
+}
+
+void __init
+pci_set_bus_ranges(void)
+{
+       struct pci_bus *bus;
+       for (bus = pci_root; bus; bus = bus->next)
+               pbus_set_ranges(bus, NULL);
+}
+
+static void
+pdev_fixup_irq(struct pci_dev *dev,
+              u8 (*swizzle)(struct pci_dev *, u8 *),
+              int (*map_irq)(struct pci_dev *, u8, u8))
+{
+       u8 pin, slot;
+       int irq;
+
+       /* If this device is not on the primary bus, we need to figure out
+          which interrupt pin it will come in on.   We know which slot it
+          will come in on 'cos that slot is where the bridge is.   Each
+          time the interrupt line passes through a PCI-PCI bridge we must
+          apply the swizzle function.  */
+
+       pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+       /* Cope with 0 and illegal. */
+       if (pin == 0 || pin > 4)
+               pin = 1;
+
+       /* Follow the chain of bridges, swizzling as we go.  */
+       slot = (*swizzle)(dev, &pin);
+
+       irq = (*map_irq)(dev, slot, pin);
+       if (irq == -1)
+               irq = 0;
+       dev->irq = irq;
+
+       DBGC(("PCI fixup irq: (%s) got %d\n", dev->name, dev->irq));
+
+       /* Always tell the device, so the driver knows what is
+          the real IRQ to use; the device does not use it. */
+       pcibios_update_irq(dev, irq);
+}
+
+void __init
+pci_fixup_irqs(u8 (*swizzle)(struct pci_dev *, u8 *),
+              int (*map_irq)(struct pci_dev *, u8, u8))
+{
+       struct pci_dev *dev;
+       for (dev = pci_devices; dev; dev = dev->next)
+               pdev_fixup_irq(dev, swizzle, map_irq);
+}
diff --git a/drivers/pci/syscall.c b/drivers/pci/syscall.c
new file mode 100644 (file)
index 0000000..4114f8d
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ *     pci_syscall.c
+ *
+ * For architectures where we want to allow direct access
+ * to the PCI config stuff - it would probably be preferable
+ * on PCs too, but there people just do it by hand with the
+ * magic northbridge registers..
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/smp_lock.h>
+#include <asm/uaccess.h>
+
+
+asmlinkage long
+sys_pciconfig_read(unsigned long bus, unsigned long dfn,
+                  unsigned long off, unsigned long len, void *buf)
+{
+       struct pci_dev *dev;
+       u8 byte;
+       u16 word;
+       u32 dword;
+       long err, cfg_ret;
+
+       err = -EPERM;
+       if (!capable(CAP_SYS_ADMIN))
+               goto error;
+
+       err = -ENODEV;
+       dev = pci_find_slot(bus, dfn);
+       if (!dev)
+               goto error;
+
+       lock_kernel();
+       switch (len) {
+       case 1:
+               cfg_ret = pci_read_config_byte(dev, off, &byte);
+               break;
+       case 2:
+               cfg_ret = pci_read_config_word(dev, off, &word);
+               break;
+       case 4:
+               cfg_ret = pci_read_config_dword(dev, off, &dword);
+               break;
+       default:
+               err = -EINVAL;
+               unlock_kernel();
+               goto error;
+       };
+       unlock_kernel();
+
+       err = -EIO;
+       if (cfg_ret != PCIBIOS_SUCCESSFUL)
+               goto error;
+
+       switch (len) {
+       case 1:
+               err = put_user(byte, (unsigned char *)buf);
+               break;
+       case 2:
+               err = put_user(word, (unsigned short *)buf);
+               break;
+       case 4:
+               err = put_user(dword, (unsigned int *)buf);
+               break;
+       };
+       return err;
+
+error:
+       /* ??? XFree86 doesn't even check the return value.  They
+          just look for 0xffffffff in the output, since that's what
+          they get instead of a machine check on x86.  */
+       switch (len) {
+       case 1:
+               put_user(-1, (unsigned char *)buf);
+               break;
+       case 2:
+               put_user(-1, (unsigned short *)buf);
+               break;
+       case 4:
+               put_user(-1, (unsigned int *)buf);
+               break;
+       };
+       return err;
+}
+
+asmlinkage long
+sys_pciconfig_write(unsigned long bus, unsigned long dfn,
+                   unsigned long off, unsigned long len, void *buf)
+{
+       struct pci_dev *dev;
+       u8 byte;
+       u16 word;
+       u32 dword;
+       int err = 0;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       if (!pcibios_present())
+               return -ENOSYS;
+
+       dev = pci_find_slot(bus, dfn);
+       if (!dev)
+               return -ENODEV;
+
+       lock_kernel();
+       switch(len) {
+       case 1:
+               err = get_user(byte, (u8 *)buf);
+               if (err)
+                       break;
+               err = pci_write_config_byte(dev, off, byte);
+               if (err != PCIBIOS_SUCCESSFUL)
+                       err = -EIO;
+               break;
+
+       case 2:
+               err = get_user(word, (u16 *)buf);
+               if (err)
+                       break;
+               err = pci_write_config_byte(dev, off, word);
+               if (err != PCIBIOS_SUCCESSFUL)
+                       err = -EIO;
+               break;
+
+       case 4:
+               err = get_user(dword, (u32 *)buf);
+               if (err)
+                       break;
+               pci_write_config_byte(dev, off, dword);
+               if (err != PCIBIOS_SUCCESSFUL)
+                       err = -EIO;
+               break;
+
+       default:
+               err = -EINVAL;
+               break;
+       };
+       unlock_kernel();
+
+       return err;
+}
diff --git a/drivers/pcmcia/Config.in b/drivers/pcmcia/Config.in
new file mode 100644 (file)
index 0000000..d0020f9
--- /dev/null
@@ -0,0 +1,12 @@
+#
+# PCMCIA bus subsystem configuration
+#
+mainmenu_option next_comment
+comment 'PCMCIA/Cardbus support'
+
+tristate 'PCMCIA/Cardbus support' CONFIG_PCMCIA
+if [ "$CONFIG_PCMCIA" != "n" ]; then
+  bool '  CardBus support' CONFIG_CARDBUS
+fi
+
+endmenu
diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile
new file mode 100644 (file)
index 0000000..579bb03
--- /dev/null
@@ -0,0 +1,28 @@
+#
+# Makefile for the kernel pcmcia subsystem (c/o David Hinds)
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now inherited from the
+# parent makes..
+
+SUB_DIRS     :=
+MOD_SUB_DIRS := $(SUB_DIRS)
+ALL_SUB_DIRS := $(SUB_DIRS)
+
+O_TARGET := pcmcia.o
+
+O_OBJS   := i82365.o tcic.o cistpl.o rsrc_mgr.o bulkmem.o
+OX_OBJS  := ds.o cs.o
+
+ifeq ($(CONFIG_CARDBUS),y)
+  O_OBJS += cardbus.o
+else
+  ifeq ($(CONFIG_CARDBUS),m)
+    MX_OBJS += cardbus.o
+  endif
+endif
+
+include $(TOPDIR)/Rules.make
diff --git a/drivers/pcmcia/bulkmem.c b/drivers/pcmcia/bulkmem.c
new file mode 100644 (file)
index 0000000..f1a8969
--- /dev/null
@@ -0,0 +1,624 @@
+/*======================================================================
+
+    PCMCIA Bulk Memory Services
+
+    bulkmem.c 1.29 1999/08/28 04:01:45
+
+    The contents of this file are subject to the Mozilla Public
+    License Version 1.1 (the "License"); you may not use this file
+    except in compliance with the License. You may obtain a copy of
+    the License at http://www.mozilla.org/MPL/
+
+    Software distributed under the License is distributed on an "AS
+    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+    implied. See the License for the specific language governing
+    rights and limitations under the License.
+
+    The initial developer of the original code is David A. Hinds
+    <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+
+    Alternatively, the contents of this file may be used under the
+    terms of the GNU Public License version 2 (the "GPL"), in which
+    case the provisions of the GPL are applicable instead of the
+    above.  If you wish to allow the use of your version of this file
+    only under the terms of the GPL and not to allow others to use
+    your version of this file under the MPL, indicate your decision
+    by deleting the provisions above and replace them with the notice
+    and other provisions required by the GPL.  If you do not delete
+    the provisions above, a recipient may use your version of this
+    file under either the MPL or the GPL.
+    
+======================================================================*/
+
+#define __NO_VERSION__
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+
+#define IN_CARD_SERVICES
+#include <pcmcia/cs_types.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/bulkmem.h>
+#include <pcmcia/cistpl.h>
+#include "cs_internal.h"
+
+/*======================================================================
+
+    This function handles submitting an MTD request, and retrying
+    requests when an MTD is busy.
+
+    An MTD request should never block.
+    
+======================================================================*/
+
+static int do_mtd_request(memory_handle_t handle, mtd_request_t *req,
+                         caddr_t buf)
+{
+    int ret, tries;
+    client_t *mtd;
+    socket_info_t *s;
+    
+    mtd = handle->mtd;
+    if (mtd == NULL)
+       return CS_GENERAL_FAILURE;
+    s = SOCKET(mtd);
+    for (tries = 0; tries < 100; tries++) {
+       mtd->event_callback_args.mtdrequest = req;
+       mtd->event_callback_args.buffer = buf;
+       ret = EVENT(mtd, CS_EVENT_MTD_REQUEST, CS_EVENT_PRI_LOW);
+       if (ret != CS_BUSY)
+           break;
+       switch (req->Status) {
+       case MTD_WAITREQ:
+           /* Not that we should ever need this... */
+           interruptible_sleep_on_timeout(&mtd->mtd_req, HZ);
+           break;
+       case MTD_WAITTIMER:
+       case MTD_WAITRDY:
+           interruptible_sleep_on_timeout(&mtd->mtd_req, req->Timeout*HZ/1000);
+           req->Function |= MTD_REQ_TIMEOUT;
+           break;
+       case MTD_WAITPOWER:
+           interruptible_sleep_on(&mtd->mtd_req);
+           break;
+       }
+       if (signal_pending(current))
+           printk(KERN_NOTICE "cs: do_mtd_request interrupted!\n");
+    }
+    if (tries == 20) {
+       printk(KERN_NOTICE "cs: MTD request timed out!\n");
+       ret = CS_GENERAL_FAILURE;
+    }
+    wake_up_interruptible(&mtd->mtd_req);
+    retry_erase_list(&mtd->erase_busy, 0);
+    return ret;
+} /* do_mtd_request */
+
+/*======================================================================
+
+    This stuff is all for handling asynchronous erase requests.  It
+    is complicated because all the retry stuff has to be dealt with
+    in timer interrupts or in the card status event handler.
+
+======================================================================*/
+
+static void insert_queue(erase_busy_t *head, erase_busy_t *entry)
+{
+    DEBUG(2, ("cs: adding 0x%p to queue 0x%p\n", entry, head));
+    entry->next = head;
+    entry->prev = head->prev;
+    head->prev->next = entry;
+    head->prev = entry;
+}
+
+static void remove_queue(erase_busy_t *entry)
+{
+    DEBUG(2, ("cs: unqueueing 0x%p\n", entry));
+    entry->next->prev = entry->prev;
+    entry->prev->next = entry->next;
+}
+
+static void retry_erase(erase_busy_t *busy, u_int cause)
+{
+    eraseq_entry_t *erase = busy->erase;
+    mtd_request_t req;
+    client_t *mtd;
+    socket_info_t *s;
+    int ret;
+
+    DEBUG(2, ("cs: trying erase request 0x%p...\n", busy));
+    if (busy->next)
+       remove_queue(busy);
+    req.Function = MTD_REQ_ERASE | cause;
+    req.TransferLength = erase->Size;
+    req.DestCardOffset = erase->Offset + erase->Handle->info.CardOffset;
+    req.MediaID = erase->Handle->MediaID;
+    mtd = erase->Handle->mtd;
+    s = SOCKET(mtd);
+    mtd->event_callback_args.mtdrequest = &req;
+    ret = EVENT(mtd, CS_EVENT_MTD_REQUEST, CS_EVENT_PRI_LOW);
+    if (ret == CS_BUSY) {
+       DEBUG(2, ("  Status = %d, requeueing.\n", req.Status));
+       switch (req.Status) {
+       case MTD_WAITREQ:
+       case MTD_WAITPOWER:
+           insert_queue(&mtd->erase_busy, busy);
+           break;
+       case MTD_WAITTIMER:
+       case MTD_WAITRDY:
+           if (req.Status == MTD_WAITRDY)
+               insert_queue(&s->erase_busy, busy);
+           busy->timeout.expires = jiffies + req.Timeout*HZ/1000;
+           add_timer(&busy->timeout);
+           break;
+       }
+    } else {
+       /* update erase queue status */
+       DEBUG(2, ("  Ret = %d\n", ret));
+       switch (ret) {
+       case CS_SUCCESS:
+           erase->State = ERASE_PASSED; break;
+       case CS_WRITE_PROTECTED:
+           erase->State = ERASE_MEDIA_WRPROT; break;
+       case CS_BAD_OFFSET:
+           erase->State = ERASE_BAD_OFFSET; break;
+       case CS_BAD_SIZE:
+           erase->State = ERASE_BAD_SIZE; break;
+       case CS_NO_CARD:
+           erase->State = ERASE_BAD_SOCKET; break;
+       default:
+           erase->State = ERASE_FAILED; break;
+       }
+       busy->client->event_callback_args.info = erase;
+       EVENT(busy->client, CS_EVENT_ERASE_COMPLETE, CS_EVENT_PRI_LOW);
+       kfree_s(busy, sizeof(*busy));
+       /* Resubmit anything waiting for a request to finish */
+       wake_up_interruptible(&mtd->mtd_req);
+       retry_erase_list(&mtd->erase_busy, 0);
+    }
+} /* retry_erase */
+
+void retry_erase_list(erase_busy_t *list, u_int cause)
+{
+    erase_busy_t tmp = *list;
+
+    DEBUG(2, ("cs: rescanning erase queue list 0x%p\n", list));
+    if (list->next == list)
+       return;
+    /* First, truncate the original list */
+    list->prev->next = &tmp;
+    list->next->prev = &tmp;
+    list->prev = list->next = list;
+    tmp.prev->next = &tmp;
+    tmp.next->prev = &tmp;
+
+    /* Now, retry each request, in order. */
+    while (tmp.next != &tmp)
+       retry_erase(tmp.next, cause);
+} /* retry_erase_list */
+
+static void handle_erase_timeout(u_long arg)
+{
+    DEBUG(0, ("cs: erase timeout for entry 0x%lx\n", arg));
+    retry_erase((erase_busy_t *)arg, MTD_REQ_TIMEOUT);
+}
+
+static void setup_erase_request(client_handle_t handle, eraseq_entry_t *erase)
+{
+    erase_busy_t *busy;
+    region_info_t *info;
+    
+    if (CHECK_REGION(erase->Handle))
+       erase->State = ERASE_BAD_SOCKET;
+    else {
+       info = &erase->Handle->info;
+       if ((erase->Offset >= info->RegionSize) ||
+           (erase->Offset & (info->BlockSize-1)))
+           erase->State = ERASE_BAD_OFFSET;
+       else if ((erase->Offset+erase->Size > info->RegionSize) ||
+                (erase->Size & (info->BlockSize-1)))
+           erase->State = ERASE_BAD_SIZE;
+       else {
+           erase->State = 1;
+           busy = kmalloc(sizeof(erase_busy_t), GFP_KERNEL);
+           busy->erase = erase;
+           busy->client = handle;
+           busy->timeout.prev = busy->timeout.next = NULL;
+           busy->timeout.data = (u_long)busy;
+           busy->timeout.function = &handle_erase_timeout;
+           busy->prev = busy->next = NULL;
+           retry_erase(busy, 0);
+       }
+    }
+} /* setup_erase_request */
+
+/*======================================================================
+
+    MTD helper functions
+
+======================================================================*/
+
+static int mtd_modify_window(window_handle_t win, mtd_mod_win_t *req)
+{
+    if ((win == NULL) || (win->magic != WINDOW_MAGIC))
+       return CS_BAD_HANDLE;
+    win->ctl.flags = MAP_16BIT | MAP_ACTIVE;
+    if (req->Attributes & WIN_USE_WAIT)
+       win->ctl.flags |= MAP_USE_WAIT;
+    if (req->Attributes & WIN_MEMORY_TYPE)
+       win->ctl.flags |= MAP_ATTRIB;
+    win->ctl.speed = req->AccessSpeed;
+    win->ctl.card_start = req->CardOffset;
+    win->sock->ss_entry(win->sock->sock, SS_SetMemMap, &win->ctl);
+    return CS_SUCCESS;
+}
+
+static int mtd_set_vpp(client_handle_t handle, mtd_vpp_req_t *req)
+{
+    socket_info_t *s;
+    if (CHECK_HANDLE(handle))
+       return CS_BAD_HANDLE;
+    if (req->Vpp1 != req->Vpp2)
+       return CS_BAD_VPP;
+    s = SOCKET(handle);
+    s->socket.Vpp = req->Vpp1;
+    if (s->ss_entry(s->sock, SS_SetSocket, &s->socket))
+       return CS_BAD_VPP;
+    return CS_SUCCESS;
+}
+
+static int mtd_rdy_mask(client_handle_t handle, mtd_rdy_req_t *req)
+{
+    socket_info_t *s;
+    if (CHECK_HANDLE(handle))
+       return CS_BAD_HANDLE;
+    s = SOCKET(handle);
+    if (req->Mask & CS_EVENT_READY_CHANGE)
+       s->socket.csc_mask |= SS_READY;
+    else
+       s->socket.csc_mask &= ~SS_READY;
+    if (s->ss_entry(s->sock, SS_SetSocket, &s->socket))
+       return CS_GENERAL_FAILURE;
+    return CS_SUCCESS;
+}
+
+int MTDHelperEntry(int func, void *a1, void *a2)
+{
+    switch (func) {
+    case MTDRequestWindow:
+       return CardServices(RequestWindow, a1, a2, NULL);
+    case MTDReleaseWindow:
+       return CardServices(ReleaseWindow, a1, NULL, NULL);
+    case MTDModifyWindow:
+       return mtd_modify_window(a1, a2); break;
+    case MTDSetVpp:
+       return mtd_set_vpp(a1, a2); break;
+    case MTDRDYMask:
+       return mtd_rdy_mask(a1, a2); break;
+    default:
+       return CS_UNSUPPORTED_FUNCTION; break;
+    }
+} /* MTDHelperEntry */
+
+/*======================================================================
+
+    This stuff is used by Card Services to initialize the table of
+    region info used for subsequent calls to GetFirstRegion and
+    GetNextRegion.
+    
+======================================================================*/
+
+static void setup_regions(client_handle_t handle, int attr,
+                         memory_handle_t *list)
+{
+    int i, code, has_jedec, has_geo;
+    u_int offset;
+    cistpl_device_t device;
+    cistpl_jedec_t jedec;
+    cistpl_device_geo_t geo;
+    memory_handle_t r;
+
+    DEBUG(1, ("cs: setup_regions(0x%p, %d, 0x%p)\n",
+             handle, attr, list));
+
+    code = (attr) ? CISTPL_DEVICE_A : CISTPL_DEVICE;
+    if (read_tuple(handle, code, &device) != CS_SUCCESS)
+       return;
+    code = (attr) ? CISTPL_JEDEC_A : CISTPL_JEDEC_C;
+    has_jedec = (read_tuple(handle, code, &jedec) == CS_SUCCESS);
+    if (has_jedec && (device.ndev != jedec.nid)) {
+#ifdef PCMCIA_DEBUG
+       printk(KERN_DEBUG "cs: Device info does not match JEDEC info.\n");
+#endif
+       has_jedec = 0;
+    }
+    code = (attr) ? CISTPL_DEVICE_GEO_A : CISTPL_DEVICE_GEO;
+    has_geo = (read_tuple(handle, code, &geo) == CS_SUCCESS);
+    if (has_geo && (device.ndev != geo.ngeo)) {
+#ifdef PCMCIA_DEBUG
+       printk(KERN_DEBUG "cs: Device info does not match geometry tuple.\n");
+#endif
+       has_geo = 0;
+    }
+    
+    offset = 0;
+    for (i = 0; i < device.ndev; i++) {
+       if ((device.dev[i].type != CISTPL_DTYPE_NULL) &&
+           (device.dev[i].size != 0)) {
+           r = kmalloc(sizeof(*r), GFP_KERNEL);
+           r->region_magic = REGION_MAGIC;
+           r->state = 0;
+           r->dev_info[0] = '\0';
+           r->mtd = NULL;
+           r->info.Attributes = (attr) ? REGION_TYPE_AM : 0;
+           r->info.CardOffset = offset;
+           r->info.RegionSize = device.dev[i].size;
+           r->info.AccessSpeed = device.dev[i].speed;
+           if (has_jedec) {
+               r->info.JedecMfr = jedec.id[i].mfr;
+               r->info.JedecInfo = jedec.id[i].info;
+           } else
+               r->info.JedecMfr = r->info.JedecInfo = 0;
+           if (has_geo) {
+               r->info.BlockSize = geo.geo[i].buswidth *
+                   geo.geo[i].erase_block * geo.geo[i].interleave;
+               r->info.PartMultiple =
+                   r->info.BlockSize * geo.geo[i].partition;
+           } else
+               r->info.BlockSize = r->info.PartMultiple = 1;
+           r->info.next = *list; *list = r;
+       }
+       offset += device.dev[i].size;
+    }
+} /* setup_regions */
+
+/*======================================================================
+
+    This is tricky.  When get_first_region() is called by Driver
+    Services, we initialize the region info table in the socket
+    structure.  When it is called by an MTD, we can just scan the
+    table for matching entries.
+    
+======================================================================*/
+
+static int match_region(client_handle_t handle, memory_handle_t list,
+                       region_info_t *match)
+{
+    while (list != NULL) {
+       if (!(handle->Attributes & INFO_MTD_CLIENT) ||
+           (strcmp(handle->dev_info, list->dev_info) == 0)) {
+           *match = list->info;
+           return CS_SUCCESS;
+       }
+       list = list->info.next;
+    }
+    return CS_NO_MORE_ITEMS;
+} /* match_region */
+
+int get_first_region(client_handle_t handle, region_info_t *rgn)
+{
+    socket_info_t *s = SOCKET(handle);
+    if (CHECK_HANDLE(handle))
+       return CS_BAD_HANDLE;
+    
+    if ((handle->Attributes & INFO_MASTER_CLIENT) &&
+       (!(s->state & SOCKET_REGION_INFO))) {
+       setup_regions(handle, 0, &s->c_region);
+       setup_regions(handle, 1, &s->a_region);
+       s->state |= SOCKET_REGION_INFO;
+    }
+
+    if (rgn->Attributes & REGION_TYPE_AM)
+       return match_region(handle, s->a_region, rgn);
+    else
+       return match_region(handle, s->c_region, rgn);
+} /* get_first_region */
+
+int get_next_region(client_handle_t handle, region_info_t *rgn)
+{
+    if (CHECK_HANDLE(handle))
+       return CS_BAD_HANDLE;
+    return match_region(handle, rgn->next, rgn);
+} /* get_next_region */
+
+/*======================================================================
+
+    Connect an MTD with a memory region.
+    
+======================================================================*/
+
+int register_mtd(client_handle_t handle, mtd_reg_t *reg)
+{
+    memory_handle_t list;
+    socket_info_t *s;
+    
+    if (CHECK_HANDLE(handle))
+       return CS_BAD_HANDLE;
+    s = SOCKET(handle);
+    if (reg->Attributes & REGION_TYPE_AM)
+       list = s->a_region;
+    else
+       list = s->c_region;
+    DEBUG(1, ("cs: register_mtd(0x%p, '%s', 0x%x)\n",
+             handle, handle->dev_info, reg->Offset));
+    while (list) {
+       if (list->info.CardOffset == reg->Offset) break;
+       list = list->info.next;
+    }
+    if (list && (list->mtd == NULL) &&
+       (strcmp(handle->dev_info, list->dev_info) == 0)) {
+       list->info.Attributes = reg->Attributes;
+       list->MediaID = reg->MediaID;
+       list->mtd = handle;
+       handle->mtd_count++;
+       return CS_SUCCESS;
+    } else
+       return CS_BAD_OFFSET;
+} /* register_mtd */
+
+/*======================================================================
+
+    
+    
+======================================================================*/
+
+int register_erase_queue(client_handle_t *handle, eraseq_hdr_t *header)
+{
+    eraseq_t *queue;
+
+    if ((handle == NULL) || CHECK_HANDLE(*handle))
+       return CS_BAD_HANDLE;
+    queue = kmalloc(sizeof(*queue), GFP_KERNEL);
+    queue->eraseq_magic = ERASEQ_MAGIC;
+    queue->handle = *handle;
+    queue->count = header->QueueEntryCnt;
+    queue->entry = header->QueueEntryArray;
+    *handle = (client_handle_t)queue;
+    return CS_SUCCESS;
+} /* register_erase_queue */
+
+int deregister_erase_queue(eraseq_handle_t eraseq)
+{
+    int i;
+    if (CHECK_ERASEQ(eraseq))
+       return CS_BAD_HANDLE;
+    for (i = 0; i < eraseq->count; i++)
+       if (ERASE_IN_PROGRESS(eraseq->entry[i].State)) break;
+    if (i < eraseq->count)
+       return CS_BUSY;
+    eraseq->eraseq_magic = 0;
+    kfree_s(eraseq, sizeof(*eraseq));
+    return CS_SUCCESS;
+} /* deregister_erase_queue */
+
+int check_erase_queue(eraseq_handle_t eraseq)
+{
+    int i;
+    if (CHECK_ERASEQ(eraseq))
+       return CS_BAD_HANDLE;
+    for (i = 0; i < eraseq->count; i++)
+       if (eraseq->entry[i].State == ERASE_QUEUED)
+           setup_erase_request(eraseq->handle, &eraseq->entry[i]);
+    return CS_SUCCESS;
+} /* check_erase_queue */
+
+/*======================================================================
+
+    Look up the memory region matching the request, and return a
+    memory handle.
+    
+======================================================================*/
+
+int open_memory(client_handle_t *handle, open_mem_t *open)
+{
+    socket_info_t *s;
+    memory_handle_t region;
+    
+    if ((handle == NULL) || CHECK_HANDLE(*handle))
+       return CS_BAD_HANDLE;
+    s = SOCKET(*handle);
+    if (open->Attributes & MEMORY_TYPE_AM)
+       region = s->a_region;
+    else
+       region = s->c_region;
+    while (region) {
+       if (region->info.CardOffset == open->Offset) break;
+       region = region->info.next;
+    }
+    if (region && region->mtd) {
+       *handle = (client_handle_t)region;
+       DEBUG(1, ("cs: open_memory(0x%p, 0x%x) = 0x%p\n",
+                 handle, open->Offset, region));
+       return CS_SUCCESS;
+    } else
+       return CS_BAD_OFFSET;
+} /* open_memory */
+
+/*======================================================================
+
+    Close a memory handle from an earlier call to OpenMemory.
+    
+    For the moment, I don't think this needs to do anything.
+    
+======================================================================*/
+
+int close_memory(memory_handle_t handle)
+{
+    DEBUG(1, ("cs: close_memory(0x%p)\n", handle));
+    if (CHECK_REGION(handle))
+       return CS_BAD_HANDLE;
+    return CS_SUCCESS;
+} /* close_memory */
+
+/*======================================================================
+
+    Read from a memory device, using a handle previously returned
+    by a call to OpenMemory.
+    
+======================================================================*/
+
+int read_memory(memory_handle_t handle, mem_op_t *req, caddr_t buf)
+{
+    mtd_request_t mtd;
+    if (CHECK_REGION(handle))
+       return CS_BAD_HANDLE;
+    if (req->Offset >= handle->info.RegionSize)
+       return CS_BAD_OFFSET;
+    if (req->Offset+req->Count > handle->info.RegionSize)
+       return CS_BAD_SIZE;
+    
+    mtd.SrcCardOffset = req->Offset + handle->info.CardOffset;
+    mtd.TransferLength = req->Count;
+    mtd.MediaID = handle->MediaID;
+    mtd.Function = MTD_REQ_READ;
+    if (req->Attributes & MEM_OP_BUFFER_KERNEL)
+       mtd.Function |= MTD_REQ_KERNEL;
+    return do_mtd_request(handle, &mtd, buf);
+} /* read_memory */
+
+/*======================================================================
+
+    Write to a memory device, using a handle previously returned by
+    a call to OpenMemory.
+    
+======================================================================*/
+
+int write_memory(memory_handle_t handle, mem_op_t *req, caddr_t buf)
+{
+    mtd_request_t mtd;
+    if (CHECK_REGION(handle))
+       return CS_BAD_HANDLE;
+    if (req->Offset >= handle->info.RegionSize)
+       return CS_BAD_OFFSET;
+    if (req->Offset+req->Count > handle->info.RegionSize)
+       return CS_BAD_SIZE;
+    
+    mtd.DestCardOffset = req->Offset + handle->info.CardOffset;
+    mtd.TransferLength = req->Count;
+    mtd.MediaID = handle->MediaID;
+    mtd.Function = MTD_REQ_WRITE;
+    if (req->Attributes & MEM_OP_BUFFER_KERNEL)
+       mtd.Function |= MTD_REQ_KERNEL;
+    return do_mtd_request(handle, &mtd, buf);
+} /* write_memory */
+
+/*======================================================================
+
+    
+======================================================================*/
+
+int copy_memory(memory_handle_t handle, copy_op_t *req)
+{
+    if (CHECK_REGION(handle))
+       return CS_BAD_HANDLE;
+    return CS_UNSUPPORTED_FUNCTION;
+} /* close_memory */
+
diff --git a/drivers/pcmcia/cardbus.c b/drivers/pcmcia/cardbus.c
new file mode 100644 (file)
index 0000000..a066d18
--- /dev/null
@@ -0,0 +1,602 @@
+/*======================================================================
+  
+    Cardbus device configuration
+    
+    cardbus.c 1.55 1999/08/28 04:01:45
+
+    The contents of this file are subject to the Mozilla Public
+    License Version 1.1 (the "License"); you may not use this file
+    except in compliance with the License. You may obtain a copy of
+    the License at http://www.mozilla.org/MPL/
+
+    Software distributed under the License is distributed on an "AS
+    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+    implied. See the License for the specific language governing
+    rights and limitations under the License.
+
+    The initial developer of the original code is David A. Hinds
+    <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+
+    Alternatively, the contents of this file may be used under the
+    terms of the GNU Public License version 2 (the "GPL"), in which
+    case the provisions of the GPL are applicable instead of the
+    above.  If you wish to allow the use of your version of this file
+    only under the terms of the GPL and not to allow others to use
+    your version of this file under the MPL, indicate your decision
+    by deleting the provisions above and replace them with the notice
+    and other provisions required by the GPL.  If you do not delete
+    the provisions above, a recipient may use your version of this
+    file under either the MPL or the GPL.
+    
+    These routines handle allocating resources for Cardbus cards, as
+    well as setting up and shutting down Cardbus sockets.  They are
+    called from cs.c in response to Request/ReleaseConfiguration and
+    Request/ReleaseIO calls.
+    
+======================================================================*/
+
+#define __NO_VERSION__
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#ifndef PCMCIA_DEBUG
+#define PCMCIA_DEBUG 1
+#endif
+static int pc_debug = PCMCIA_DEBUG;
+
+#define IN_CARD_SERVICES
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/bulkmem.h>
+#include <pcmcia/cistpl.h>
+#include "cs_internal.h"
+#include "rsrc_mgr.h"
+
+/*====================================================================*/
+
+#define FIND_FIRST_BIT(n)      ((n) - ((n) & ((n)-1)))
+
+#define pci_readb              pcibios_read_config_byte
+#define pci_writeb             pcibios_write_config_byte
+#define pci_readw              pcibios_read_config_word
+#define pci_writew             pcibios_write_config_word
+#define pci_readl              pcibios_read_config_dword
+#define pci_writel             pcibios_write_config_dword
+
+#define CB_BAR(n)              (PCI_BASE_ADDRESS_0+(4*(n)))
+#define CB_ROM_BASE            0x0030
+
+/* Offsets in the Expansion ROM Image Header */
+#define ROM_SIGNATURE          0x0000  /* 2 bytes */
+#define ROM_DATA_PTR           0x0018  /* 2 bytes */
+
+/* Offsets in the CardBus PC Card Data Structure */
+#define PCDATA_SIGNATURE       0x0000  /* 4 bytes */
+#define PCDATA_VPD_PTR         0x0008  /* 2 bytes */
+#define PCDATA_LENGTH          0x000a  /* 2 bytes */
+#define PCDATA_REVISION                0x000c
+#define PCDATA_IMAGE_SZ                0x0010  /* 2 bytes */
+#define PCDATA_ROM_LEVEL       0x0012  /* 2 bytes */
+#define PCDATA_CODE_TYPE       0x0014
+#define PCDATA_INDICATOR       0x0015
+
+typedef struct cb_config_t {
+    u_int              size[7];
+    struct pci_dev     dev;
+} cb_config_t;
+
+#define BASE(dev,n)    ((dev).resource[n].start)
+#define ROM(dev)       ((dev).resource[6].start)
+
+/* There are three classes of bridge maps: IO ports,
+   non-prefetchable memory, and prefetchable memory */
+typedef enum { B_IO, B_M1, B_M2 } bridge_type;
+
+/*=====================================================================
+
+    Expansion ROM's have a special layout, and pointers specify an
+    image number and an offset within that image.  check_rom()
+    verifies that the expansion ROM exists and has the standard
+    layout.  xlate_rom_addr() converts an image/offset address to an
+    absolute offset from the ROM's base address.
+    
+=====================================================================*/
+
+static int check_rom(u_char *b, u_long len)
+{
+    u_int img = 0, ofs = 0, sz;
+    u_short data;
+    DEBUG(0, ("ROM image dump:\n"));
+    while ((readb(b) == 0x55) && (readb(b+1) == 0xaa)) {
+       data = readb(b+ROM_DATA_PTR) +
+           (readb(b+ROM_DATA_PTR+1) << 8);
+       sz = 512 * (readb(b+data+PCDATA_IMAGE_SZ) +
+                   (readb(b+data+PCDATA_IMAGE_SZ+1) << 8));
+       DEBUG(0, ("  image %d: 0x%06x-0x%06x, signature %c%c%c%c\n",
+                 img, ofs, ofs+sz-1,
+                 readb(b+data+PCDATA_SIGNATURE),
+                 readb(b+data+PCDATA_SIGNATURE+1),
+                 readb(b+data+PCDATA_SIGNATURE+2),
+                 readb(b+data+PCDATA_SIGNATURE+3)));
+       ofs += sz; img++;
+       if ((readb(b+data+PCDATA_INDICATOR) & 0x80) ||
+           (sz == 0) || (ofs >= len)) break;
+       b += sz;
+    }
+    return img;
+}
+
+static u_int xlate_rom_addr(u_char *b, u_int addr)
+{
+    u_int img = 0, ofs = 0, sz;
+    u_short data;
+    while ((readb(b) == 0x55) && (readb(b+1) == 0xaa)) {
+       if (img == (addr >> 28))
+           return (addr & 0x0fffffff) + ofs;
+       data = readb(b+ROM_DATA_PTR) + (readb(b+ROM_DATA_PTR+1) << 8);
+       sz = 512 * (readb(b+data+PCDATA_IMAGE_SZ) +
+                   (readb(b+data+PCDATA_IMAGE_SZ+1) << 8));
+       if ((sz == 0) || (readb(b+data+PCDATA_INDICATOR) & 0x80))
+           break;
+       b += sz; ofs += sz; img++;
+    }
+    return 0;
+}
+
+/*=====================================================================
+
+    These are similar to setup_cis_mem and release_cis_mem for 16-bit
+    cards.  The "result" that is used externally is the cb_cis_virt
+    pointer in the socket_info_t structure.
+    
+=====================================================================*/
+
+int cb_setup_cis_mem(socket_info_t *s, int space)
+{
+    cb_bridge_map *m = &s->cb_cis_map;
+    u_long base = 0;
+    u_int sz, br;
+
+    if (space == s->cb_cis_space)
+       return CS_SUCCESS;
+    else if (s->cb_cis_space != 0)
+       cb_release_cis_mem(s);
+    DEBUG(1, ("cs: cb_setup_cis_mem(space %d)\n", space));
+    /* If socket is configured, then use existing memory mapping */
+    if (s->lock_count) {
+       s->cb_cis_virt =
+           ioremap(BASE(s->cb_config[0].dev, space-1),
+                   s->cb_config[0].size[space-1] & ~3);
+       s->cb_cis_space = space;
+       return CS_SUCCESS;
+    }
+    
+    /* Not configured?  Then set up temporary map */
+    br = (space == 7) ? CB_ROM_BASE : CB_BAR(space-1);
+    pci_writel(s->cap.cardbus, 0, br, 0xffffffff);
+    pci_readl(s->cap.cardbus, 0, br, &sz);
+    sz &= PCI_BASE_ADDRESS_MEM_MASK;
+    sz = FIND_FIRST_BIT(sz);
+    if (sz < PAGE_SIZE) sz = PAGE_SIZE;
+    if (find_mem_region(&base, sz, "cb_enabler", sz, 0) != 0) {
+       printk(KERN_NOTICE "cs: could not allocate %dK memory for"
+              " CardBus socket %d\n", sz/1024, s->sock);
+       return CS_OUT_OF_RESOURCE;
+    }
+    s->cb_cis_space = space;
+    s->cb_cis_virt = ioremap(base, sz);
+    DEBUG(1, ("  phys 0x%08lx-0x%08lx, virt 0x%08lx\n",
+             base, base+sz-1, (u_long)s->cb_cis_virt));
+    pci_writel(s->cap.cardbus, 0, br, base | 1);
+    pci_writeb(s->cap.cardbus, 0, PCI_COMMAND, PCI_COMMAND_MEMORY);
+    m->map = 0; m->flags = MAP_ACTIVE;
+    m->start = base; m->stop = base+sz-1;
+    s->ss_entry(s->sock, SS_SetBridge, m);
+    if ((space == 7) && (check_rom(s->cb_cis_virt, sz) == 0)) {
+       printk(KERN_NOTICE "cs: no valid ROM images found!\n");
+       return CS_READ_FAILURE;
+    }
+    return CS_SUCCESS;
+}
+
+void cb_release_cis_mem(socket_info_t *s)
+{
+    cb_bridge_map *m = &s->cb_cis_map;
+    u_int br;
+    if (s->cb_cis_virt) {
+       DEBUG(1, ("cs: cb_release_cis_mem()\n"));
+       iounmap(s->cb_cis_virt);
+       s->cb_cis_virt = NULL;
+       s->cb_cis_space = 0;
+    }
+    if (m->start) {
+       /* This is overkill: we probably only need to release the
+          memory region, but the rest should be safe */
+       br = (s->cb_cis_space == 7) ?
+           CB_ROM_BASE : CB_BAR(s->cb_cis_space-1);
+       m->map = 0; m->flags = 0;
+       s->ss_entry(s->sock, SS_SetBridge, m);
+       pci_writeb(s->cap.cardbus, 0, PCI_COMMAND, 0);
+       pci_writel(s->cap.cardbus, 0, br, 0);
+       release_mem_region(m->start, m->stop - m->start + 1);
+       m->start = 0;
+    }
+}
+
+/*=====================================================================
+
+    This is used by the CIS processing code to read CIS information
+    from a CardBus device.
+    
+=====================================================================*/
+
+void read_cb_mem(socket_info_t *s, u_char fn, int space,
+                u_int addr, u_int len, void *ptr)
+{
+    DEBUG(3, ("cs: read_cb_mem(%d, %#x, %u)\n", space, addr, len));
+    if (space == 0) {
+       for (; len; addr++, ptr++, len--)
+           pci_readb(s->cap.cardbus, fn, addr, (u_char *)ptr);
+    } else {
+       if (cb_setup_cis_mem(s, space) != 0) {
+           memset(ptr, 0xff, len);
+           return;
+       }
+       if (space == 7) {
+           addr = xlate_rom_addr(s->cb_cis_virt, addr);
+           if (addr == 0) {
+               memset(ptr, 0xff, len);
+               return;
+           }
+       }
+       if (s->cb_cis_virt != NULL)
+           for (; len; addr++, ptr++, len--)
+               *(u_char *)ptr = readb(s->cb_cis_virt+addr);
+    }
+}
+
+/*=====================================================================
+
+    cb_config() has the job of allocating all system resources that
+    a Cardbus card requires.  Rather than using the CIS (which seems
+    to not always be present), it treats the card as an ordinary PCI
+    device, and probes the base address registers to determine each
+    function's IO and memory space needs.
+
+    It is called from the RequestIO card service.
+    
+======================================================================*/
+
+int cb_config(socket_info_t *s)
+{
+    u_short vend, v, dev;
+    u_char i, j, fn, bus = s->cap.cardbus, *name;
+    u_int sz, align, m, mask[3], num[3], base[3];
+    cb_config_t *c;
+    int irq, try, ret;
+    
+    pci_readw(bus, 0, PCI_VENDOR_ID, &vend);
+    pci_readw(bus, 0, PCI_DEVICE_ID, &dev);
+    printk(KERN_INFO "cs: cb_config(bus %d): vendor 0x%04x, "
+          "device 0x%04x\n", bus, vend, dev);
+
+    pci_readb(bus, 0, PCI_HEADER_TYPE, &fn);
+    if (fn & 0x80) {
+       /* Count functions */
+       for (fn = 0; fn < 8; fn++) {
+           pci_readw(bus, fn, PCI_VENDOR_ID, &v);
+           if (v != vend) break;
+       }
+    } else fn = 1;
+    s->functions = fn;
+    
+    c = kmalloc(fn * sizeof(struct cb_config_t), GFP_KERNEL);
+    memset(c, 0, fn * sizeof(struct cb_config_t));
+    s->cb_config = c;
+
+    for (i = 0; i < fn; i++) {
+       c[i].dev.bus = s->cap.cb_bus;
+       if (i < fn-1) {
+           c[i].dev.sibling = c[i].dev.next = &c[i+1].dev;
+       }
+       c[i].dev.devfn = i;
+       c[i].dev.vendor = vend; c[i].dev.device = dev;
+       pci_readl(bus, i, PCI_CLASS_REVISION, &c[i].dev.class);
+       c[i].dev.class >>= 8;
+       pci_readb(bus, i, PCI_HEADER_TYPE, &j);
+       c[i].dev.hdr_type = j;
+    }
+    s->cap.cb_bus->devices = &c[0].dev;
+    
+    /* Determine IO and memory space needs */
+    num[B_IO] = num[B_M1] = num[B_M2] = 0;
+    mask[B_IO] = mask[B_M1] = mask[B_M2] = 0;
+    for (i = 0; i < fn; i++) {
+       for (j = 0; j < 6; j++) {
+           pci_writel(bus, i, CB_BAR(j), 0xffffffff);
+           pci_readl(bus, i, CB_BAR(j), &sz);
+           if (sz == 0) continue;
+           if (sz & PCI_BASE_ADDRESS_SPACE) {
+               m = B_IO;
+               sz &= PCI_BASE_ADDRESS_IO_MASK;
+           } else {
+               m = (sz & PCI_BASE_ADDRESS_MEM_PREFETCH) ? B_M2 : B_M1;
+               sz &= PCI_BASE_ADDRESS_MEM_MASK;
+           }
+           sz = FIND_FIRST_BIT(sz);
+           c[i].size[j] = sz | m;
+           if (m && (sz < PAGE_SIZE)) sz = PAGE_SIZE;
+           num[m] += sz; mask[m] |= sz;
+       }
+       pci_writel(bus, i, CB_ROM_BASE, 0xffffffff);
+       pci_readl(bus, i, CB_ROM_BASE, &sz);
+       if (sz != 0) {
+           sz = FIND_FIRST_BIT(sz & ~0x00000001);
+           c[i].size[6] = sz | B_M1;
+           if (sz < PAGE_SIZE) sz = PAGE_SIZE;
+           num[B_M1] += sz; mask[B_M1] |= sz;
+       }
+    }
+
+    /* Allocate system resources */
+    name = "cb_enabler";
+    s->io[0].NumPorts = num[B_IO];
+    s->io[0].BasePort = 0;
+    if (num[B_IO]) {
+       if (find_io_region(&s->io[0].BasePort, num[B_IO], name) != 0) {
+           printk(KERN_NOTICE "cs: could not allocate %d IO ports for"
+                  " CardBus socket %d\n", num[B_IO], s->sock);
+           goto failed;
+       }
+       base[B_IO] = s->io[0].BasePort + num[B_IO];
+    }
+    s->win[0].size = num[B_M1];
+    s->win[0].base = 0;
+    if (num[B_M1]) {
+       if (find_mem_region(&s->win[0].base, num[B_M1],
+                           name, num[B_M1], 0) != 0) {
+           printk(KERN_NOTICE "cs: could not allocate %dK memory for"
+                  " CardBus socket %d\n", num[B_M1]/1024, s->sock);
+           goto failed;
+       }
+       base[B_M1] = s->win[0].base + num[B_M1];
+    }
+    s->win[1].size = num[B_M2];
+    s->win[1].base = 0;
+    if (num[B_M2]) {
+       if (find_mem_region(&s->win[1].base, num[B_M2],
+                           name, num[B_M2], 0) != 0) {
+           printk(KERN_NOTICE "cs: could not allocate %dK memory for"
+                  " CardBus socket %d\n", num[B_M2]/1024, s->sock);
+           goto failed;
+       }
+       base[B_M2] = s->win[1].base + num[B_M2];
+    }
+    
+    /* Set up base address registers */
+    while (mask[B_IO] | mask[B_M1] | mask[B_M2]) {
+       num[B_IO] = FIND_FIRST_BIT(mask[B_IO]); mask[B_IO] -= num[B_IO];
+       num[B_M1] = FIND_FIRST_BIT(mask[B_M1]); mask[B_M1] -= num[B_M1];
+       num[B_M2] = FIND_FIRST_BIT(mask[B_M2]); mask[B_M2] -= num[B_M2];
+       for (i = 0; i < fn; i++) {
+           for (j = 0; j < 7; j++) {
+               sz = c[i].size[j];
+               m = sz & 3; sz &= ~3;
+               align = (m && (sz < PAGE_SIZE)) ? PAGE_SIZE : sz;
+               if (sz && (align == num[m])) {
+                   base[m] -= align;
+                   if (j < 6)
+                       printk(KERN_INFO "  fn %d bar %d: ", i, j+1);
+                   else
+                       printk(KERN_INFO "  fn %d rom: ", i);
+                   printk("%s 0x%x-0x%x\n", (m) ? "mem" : "io",
+                          base[m], base[m]+sz-1);
+                   BASE(c[i].dev, j) = base[m];
+               }
+           }
+       }
+    }
+    
+    /* Allocate interrupt if needed */
+    s->irq.AssignedIRQ = irq = 0; ret = -1;
+    for (i = 0; i < fn; i++) {
+       pci_readb(bus, i, PCI_INTERRUPT_PIN, &j);
+       if (j == 0) continue;
+       if (irq == 0) {
+           if (s->cap.irq_mask & (1 << s->cap.pci_irq)) {
+               irq = s->cap.pci_irq;
+               ret = 0;
+           }
+#ifdef CONFIG_ISA
+           else
+               for (try = 0; try < 2; try++) {
+                   for (irq = 0; irq < 32; irq++)
+                       if ((s->cap.irq_mask >> irq) & 1) {
+                           ret = try_irq(IRQ_TYPE_EXCLUSIVE, irq, try);
+                           if (ret == 0) break;
+                       }
+                   if (ret == 0) break;
+               }
+           if (ret != 0) {
+               printk(KERN_NOTICE "cs: could not allocate interrupt"
+                      " for CardBus socket %d\n", s->sock);
+               goto failed;
+           }
+#endif
+           s->irq.AssignedIRQ = irq;
+       }
+    }
+    c[0].dev.irq = irq;
+    
+    return CS_SUCCESS;
+
+failed:
+    cb_release(s);
+    return CS_OUT_OF_RESOURCE;
+}
+
+/*======================================================================
+
+    cb_release() releases all the system resources (IO and memory
+    space, and interrupt) committed for a Cardbus card by a prior call
+    to cb_config().
+
+    It is called from the ReleaseIO() service.
+    
+======================================================================*/
+
+void cb_release(socket_info_t *s)
+{
+    cb_config_t *c = s->cb_config;
+    
+    DEBUG(0, ("cs: cb_release(bus %d)\n", s->cap.cardbus));
+    
+    if (s->win[0].size > 0)
+       release_mem_region(s->win[0].base, s->win[0].size);
+    if (s->win[1].size > 0)
+       release_mem_region(s->win[1].base, s->win[1].size);
+    if (s->io[0].NumPorts > 0)
+       release_region(s->io[0].BasePort, s->io[0].NumPorts);
+    s->io[0].NumPorts = 0;
+#ifdef CONFIG_ISA
+    if ((c[0].dev.irq != 0) && (c[0].dev.irq != s->cap.pci_irq))
+       undo_irq(IRQ_TYPE_EXCLUSIVE, c[0].dev.irq);
+#endif
+    kfree(s->cb_config);
+    s->cb_config = NULL;
+}
+
+/*=====================================================================
+
+    cb_enable() has the job of configuring a socket for a Cardbus
+    card, and initializing the card's PCI configuration registers.
+
+    It first sets up the Cardbus bridge windows, for IO and memory
+    accesses.  Then, it initializes each card function's base address
+    registers, interrupt line register, and command register.
+
+    It is called as part of the RequestConfiguration card service.
+    It should be called after a previous call to cb_config() (via the
+    RequestIO service).
+    
+======================================================================*/
+
+void cb_enable(socket_info_t *s)
+{
+    u_char i, j, bus = s->cap.cardbus;
+    cb_config_t *c = s->cb_config;
+    
+    DEBUG(0, ("cs: cb_enable(bus %d)\n", bus));
+    
+    /* Configure bridge */
+    if (s->cb_cis_map.start)
+       cb_release_cis_mem(s);
+    for (i = 0; i < 3; i++) {
+       cb_bridge_map m;
+       switch (i) {
+       case B_IO:
+           m.map = 0; m.flags = MAP_IOSPACE | MAP_ACTIVE;
+           m.start = s->io[0].BasePort;
+           m.stop = m.start + s->io[0].NumPorts - 1;
+           break;
+       case B_M1:
+           m.map = 0; m.flags = MAP_ACTIVE;
+           m.start = s->win[0].base;
+           m.stop = m.start + s->win[0].size - 1;
+           break;
+       case B_M2:
+           m.map = 1; m.flags = MAP_PREFETCH | MAP_ACTIVE;
+           m.start = s->win[1].base;
+           m.stop = m.start + s->win[1].size - 1;
+           break;
+       }
+       if (m.start == 0) continue;
+       DEBUG(0, ("  bridge %s map %d (flags 0x%x): 0x%x-0x%x\n",
+                 (m.flags & MAP_IOSPACE) ? "io" : "mem",
+                 m.map, m.flags, m.start, m.stop));
+       s->ss_entry(s->sock, SS_SetBridge, &m);
+    }
+
+    /* Set up base address registers */
+    for (i = 0; i < s->functions; i++) {
+       for (j = 0; j < 6; j++) {
+           if (BASE(c[i].dev, j) != 0)
+               pci_writel(bus, i, CB_BAR(j), BASE(c[i].dev, j));
+       }
+       if (ROM(c[i].dev) != 0)
+           pci_writel(bus, i, CB_ROM_BASE, ROM(c[i].dev) | 1);
+    }
+
+    /* Set up PCI interrupt and command registers */
+    for (i = 0; i < s->functions; i++) {
+       pci_writeb(bus, i, PCI_COMMAND, PCI_COMMAND_MASTER |
+                  PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+       pci_writeb(bus, i, PCI_CACHE_LINE_SIZE, 8);
+    }
+    
+    if (s->irq.AssignedIRQ) {
+       for (i = 0; i < s->functions; i++)
+           pci_writeb(bus, i, PCI_INTERRUPT_LINE,
+                      s->irq.AssignedIRQ);
+       s->socket.io_irq = s->irq.AssignedIRQ;
+       s->ss_entry(s->sock, SS_SetSocket, &s->socket);
+    }
+
+    /* Link into PCI device chain */
+    c[s->functions-1].dev.next = pci_devices;
+    pci_devices = &c[0].dev;
+    for (i = 0; i < s->functions; i++)
+       pci_proc_attach_device(&c[i].dev);
+}
+
+/*======================================================================
+
+    cb_disable() unconfigures a Cardbus card previously set up by
+    cb_enable().
+
+    It is called from the ReleaseConfiguration service.
+    
+======================================================================*/
+
+void cb_disable(socket_info_t *s)
+{
+    u_char i;
+    cb_bridge_map m = { 0, 0, 0, 0xffff };
+    struct pci_dev **p, *q;
+    cb_config_t *c = s->cb_config;
+    
+    /* Unlink from PCI device chain */
+    for (p = &pci_devices; *p; p = &((*p)->next))
+       if (*p == &c[0].dev) break;
+    for (q = *p; q; q = q->next) {
+       if (q->bus != (*p)->bus) break;
+       pci_proc_detach_device(q);
+    }
+    if (*p) *p = q;
+    s->cap.cb_bus->devices = NULL;
+    
+    DEBUG(0, ("cs: cb_disable(bus %d)\n", s->cap.cardbus));
+    
+    /* Turn off bridge windows */
+    if (s->cb_cis_map.start)
+       cb_release_cis_mem(s);
+    for (i = 0; i < 3; i++) {
+       switch (i) {
+       case B_IO: m.map = 0; m.flags = MAP_IOSPACE; break;
+       case B_M1: m.map = m.flags = 0; break;
+       case B_M2: m.map = 1; m.flags = 0; break;
+       }
+       s->ss_entry(s->sock, SS_SetBridge, &m);
+    }
+}
diff --git a/drivers/pcmcia/cb_enabler.c b/drivers/pcmcia/cb_enabler.c
new file mode 100644 (file)
index 0000000..b8ac90e
--- /dev/null
@@ -0,0 +1,405 @@
+/*======================================================================
+
+    Cardbus device enabler
+
+    cb_enabler.c 1.21 1999/08/28 04:01:45
+
+    The contents of this file are subject to the Mozilla Public
+    License Version 1.1 (the "License"); you may not use this file
+    except in compliance with the License. You may obtain a copy of
+    the License at http://www.mozilla.org/MPL/
+
+    Software distributed under the License is distributed on an "AS
+    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+    implied. See the License for the specific language governing
+    rights and limitations under the License.
+
+    The initial developer of the original code is David A. Hinds
+    <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+
+    Alternatively, the contents of this file may be used under the
+    terms of the GNU Public License version 2 (the "GPL"), in which
+    case the provisions of the GPL are applicable instead of the
+    above.  If you wish to allow the use of your version of this file
+    only under the terms of the GPL and not to allow others to use
+    your version of this file under the MPL, indicate your decision
+    by deleting the provisions above and replace them with the notice
+    and other provisions required by the GPL.  If you do not delete
+    the provisions above, a recipient may use your version of this
+    file under either the MPL or the GPL.
+    
+    The general idea:
+
+    A client driver registers using register_driver().  This module
+    then creates a Card Services pseudo-client and registers it, and
+    configures the socket if this is the first client.  It then
+    invokes the appropriate PCI client routines in response to Card
+    Services events.  
+
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+static char *version =
+"cb_enabler.c 1.21 1999/08/28 04:01:45 (David Hinds)";
+#else
+#define DEBUG(n, args...) do { } while (0)
+#endif
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/*====================================================================*/
+
+typedef struct driver_info_t {
+    dev_link_t         *(*attach)(void);
+    dev_info_t         dev_info;
+    driver_operations  *ops;
+    dev_link_t         *dev_list;
+} driver_info_t;
+
+static dev_link_t *cb_attach(int n);
+#define MK_ENTRY(fn, n) \
+static dev_link_t *fn(void) { return cb_attach(n); }
+
+#define MAX_DRIVER     4
+
+MK_ENTRY(attach_0, 0);
+MK_ENTRY(attach_1, 1);
+MK_ENTRY(attach_2, 2);
+MK_ENTRY(attach_3, 3);
+
+static driver_info_t driver[4] = {
+    { attach_0 }, { attach_1 }, { attach_2 }, { attach_3 }
+};
+
+typedef struct bus_info_t {
+    u_char             bus;
+    int                        flags, ncfg, nuse;
+    dev_link_t         *owner;
+} bus_info_t;
+
+#define DID_REQUEST    1
+#define DID_CONFIG     2
+
+static void cb_release(u_long arg);
+static int cb_event(event_t event, int priority,
+                   event_callback_args_t *args);
+
+static void cb_detach(dev_link_t *);
+
+static bus_info_t bus_table[MAX_DRIVER];
+
+
+/*====================================================================*/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+    error_info_t err = { func, ret };
+    CardServices(ReportError, handle, &err);
+}
+
+/*====================================================================*/
+
+struct dev_link_t *cb_attach(int n)
+{
+    client_reg_t client_reg;
+    dev_link_t *link;
+    int ret;
+    
+    DEBUG(0, "cb_attach(%d)\n", n);
+
+    MOD_INC_USE_COUNT;
+    link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
+    memset(link, 0, sizeof(struct dev_link_t));
+    link->release.function = &cb_release;
+    link->release.data = (u_long)link;
+
+    link->conf.IntType = INT_CARDBUS;
+    link->conf.Vcc = 33;
+
+    /* Insert into instance chain for this driver */
+    link->priv = &driver[n];
+    link->next = driver[n].dev_list;
+    driver[n].dev_list = link;
+    
+    /* Register with Card Services */
+    client_reg.dev_info = &driver[n].dev_info;
+    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+    client_reg.event_handler = &cb_event;
+    client_reg.EventMask =
+       CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET |
+       CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+       CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+    client_reg.Version = 0x0210;
+    client_reg.event_callback_args.client_data = link;
+    ret = CardServices(RegisterClient, &link->handle, &client_reg);
+    if (ret != 0) {
+       cs_error(link->handle, RegisterClient, ret);
+       cb_detach(link);
+       return NULL;
+    }
+    return link;
+}
+
+/*====================================================================*/
+
+static void cb_detach(dev_link_t *link)
+{
+    driver_info_t *dev = link->priv;
+    dev_link_t **linkp;
+    bus_info_t *b = (void *)link->win;
+    u_long flags;
+    
+    DEBUG(0, "cb_detach(0x%p)\n", link);
+    
+    /* Locate device structure */
+    for (linkp = &dev->dev_list; *linkp; linkp = &(*linkp)->next)
+       if (*linkp == link) break;
+    if (*linkp == NULL)
+       return;
+
+    save_flags(flags);
+    cli();
+    if (link->state & DEV_RELEASE_PENDING) {
+       del_timer(&link->release);
+       link->state &= ~DEV_RELEASE_PENDING;
+    }
+    restore_flags(flags);
+    
+    if (link->state & DEV_CONFIG)
+       cb_release((u_long)link);
+    
+    /* Don't drop Card Services connection if we are the bus owner */
+    if ((b->flags != 0) && (link == b->owner)) {
+       link->state |= DEV_STALE_LINK;
+       return;
+    }
+    
+    if (link->handle)
+       CardServices(DeregisterClient, link->handle);
+    
+    *linkp = link->next;
+    kfree_s(link, sizeof(struct dev_link_t));
+    MOD_DEC_USE_COUNT;
+}
+
+/*====================================================================*/
+
+static void cb_config(dev_link_t *link)
+{
+    client_handle_t handle = link->handle;
+    driver_info_t *drv = link->priv;
+    dev_locator_t loc;
+    bus_info_t *b;
+    config_info_t config;
+    u_char bus, devfn;
+    int i;
+    
+    DEBUG(0, "cb_config(0x%p)\n", link);
+    link->state |= DEV_CONFIG;
+
+    /* Get PCI bus info */
+    CardServices(GetConfigurationInfo, handle, &config);
+    bus = config.Option; devfn = config.Function;
+
+    /* Is this a new bus? */
+    for (i = 0; i < MAX_DRIVER; i++)
+       if (bus == bus_table[i].bus) break;
+    if (i == MAX_DRIVER) {
+       for (i = 0; i < MAX_DRIVER; i++)
+           if (bus_table[i].bus == 0) break;
+       b = &bus_table[i]; link->win = (void *)b;
+       b->bus = bus;
+       b->flags = 0;
+       b->ncfg = b->nuse = 1;
+
+       /* Special hook: CS know what to do... */
+       i = CardServices(RequestIO, handle, NULL);
+       if (i != CS_SUCCESS) {
+           cs_error(handle, RequestIO, i);
+           return;
+       }
+       b->flags |= DID_REQUEST;
+       b->owner = link;
+       i = CardServices(RequestConfiguration, handle, &link->conf);
+       if (i != CS_SUCCESS) {
+           cs_error(handle, RequestConfiguration, i);
+           return;
+       }
+       b->flags |= DID_CONFIG;
+    } else {
+       b = &bus_table[i]; link->win = (void *)b;
+       if (b->flags & DID_CONFIG) {
+           b->ncfg++; b->nuse++;
+       }
+    }
+    loc.bus = LOC_PCI;
+    loc.b.pci.bus = bus;
+    loc.b.pci.devfn = devfn;
+    link->dev = drv->ops->attach(&loc);
+    
+    link->state &= ~DEV_CONFIG_PENDING;
+}
+
+/*====================================================================*/
+
+static void cb_release(u_long arg)
+{
+    dev_link_t *link = (dev_link_t *)arg;
+    driver_info_t *drv = link->priv;
+    bus_info_t *b = (void *)link->win;
+
+    DEBUG(0, "cb_release(0x%p)\n", link);
+
+    if (link->dev != NULL) {
+       drv->ops->detach(link->dev);
+       link->dev = NULL;
+    }
+    if (link->state & DEV_CONFIG) {
+       /* If we're suspended, config was already released */
+       if (link->state & DEV_SUSPEND)
+           b->flags &= ~DID_CONFIG;
+       else if ((b->flags & DID_CONFIG) && (--b->ncfg == 0)) {
+           CardServices(ReleaseConfiguration, b->owner->handle,
+                        &b->owner->conf);
+           b->flags &= ~DID_CONFIG;
+       }
+       if ((b->flags & DID_REQUEST) && (--b->nuse == 0)) {
+           CardServices(ReleaseIO, b->owner->handle, NULL);
+           b->flags &= ~DID_REQUEST;
+       }
+       if (b->flags == 0) {
+           if (b->owner && (b->owner->state & DEV_STALE_LINK))
+               cb_detach(b->owner);
+           b->bus = 0; b->owner = NULL;
+       }
+    }
+    link->state &= ~DEV_CONFIG;
+}
+
+/*====================================================================*/
+
+static int cb_event(event_t event, int priority,
+                   event_callback_args_t *args)
+{
+    dev_link_t *link = args->client_data;
+    driver_info_t *drv = link->priv;
+    bus_info_t *b = (void *)link->win;
+    
+    DEBUG(0, "cb_event(0x%06x)\n", event);
+    
+    switch (event) {
+    case CS_EVENT_CARD_REMOVAL:
+       link->state &= ~DEV_PRESENT;
+       if (link->state & DEV_CONFIG) {
+           link->release.expires = jiffies + HZ/20;
+           link->state |= DEV_RELEASE_PENDING;
+           add_timer(&link->release);
+       }
+       break;
+    case CS_EVENT_CARD_INSERTION:
+       link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+       cb_config(link);
+       break;
+    case CS_EVENT_PM_SUSPEND:
+       link->state |= DEV_SUSPEND;
+       /* Fall through... */
+    case CS_EVENT_RESET_PHYSICAL:
+       if (link->state & DEV_CONFIG) {
+           if (drv->ops->suspend != NULL)
+               drv->ops->suspend(link->dev);
+           b->ncfg--;
+           if (b->ncfg == 0)
+               CardServices(ReleaseConfiguration, link->handle,
+                            &link->conf);
+       }
+       break;
+    case CS_EVENT_PM_RESUME:
+       link->state &= ~DEV_SUSPEND;
+       /* Fall through... */
+    case CS_EVENT_CARD_RESET:
+       if (link->state & DEV_CONFIG) {
+           b->ncfg++;
+           if (b->ncfg == 1)
+               CardServices(RequestConfiguration, link->handle,
+                            &link->conf);
+           if (drv->ops->resume != NULL)
+               drv->ops->resume(link->dev);
+       }
+       break;
+    }
+    return 0;
+}
+
+/*====================================================================*/
+
+int register_driver(struct driver_operations *ops)
+{
+    int i;
+    
+    DEBUG(0, "register_driver('%s')\n", ops->name);
+
+    for (i = 0; i < MAX_DRIVER; i++)
+       if (driver[i].ops == NULL) break;
+    if (i == MAX_DRIVER)
+       return -1;
+
+    MOD_INC_USE_COUNT;
+    driver[i].ops = ops;
+    strcpy(driver[i].dev_info, ops->name);
+    register_pccard_driver(&driver[i].dev_info, driver[i].attach,
+                          &cb_detach);
+    return 0;
+}
+
+void unregister_driver(struct driver_operations *ops)
+{
+    int i;
+
+    DEBUG(0, "unregister_driver('%s')\n", ops->name);
+    for (i = 0; i < MAX_DRIVER; i++)
+       if (driver[i].ops == ops) break;
+    if (i < MAX_DRIVER) {
+       unregister_pccard_driver(&driver[i].dev_info);
+       driver[i].ops = NULL;
+       MOD_DEC_USE_COUNT;
+    }
+}
+
+/*====================================================================*/
+
+int init_module(void) {
+    servinfo_t serv;
+    DEBUG(0, "%s\n", version);
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+       printk(KERN_NOTICE "cb_enabler: Card Services release "
+              "does not match!\n");
+       return -1;
+    }
+    return 0;
+}
+
+void cleanup_module(void) {
+    DEBUG(0, "cb_enabler: unloading\n");
+}
+
+/*====================================================================*/
diff --git a/drivers/pcmcia/cirrus.h b/drivers/pcmcia/cirrus.h
new file mode 100644 (file)
index 0000000..4352701
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * cirrus.h 1.3 1999/08/28 04:01:46
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_CIRRUS_H
+#define _LINUX_CIRRUS_H
+
+#ifndef PCI_VENDOR_ID_CIRRUS
+#define PCI_VENDOR_ID_CIRRUS           0x1013
+#endif
+#ifndef PCI_DEVICE_ID_CIRRUS_6729
+#define PCI_DEVICE_ID_CIRRUS_6729      0x1100
+#endif
+#ifndef PCI_DEVICE_ID_CIRRUS_6832
+#define PCI_DEVICE_ID_CIRRUS_6832      0x1110
+#endif
+
+#define PD67_MISC_CTL_1                0x16    /* Misc control 1 */
+#define PD67_FIFO_CTL          0x17    /* FIFO control */
+#define PD67_MISC_CTL_2                0x1E    /* Misc control 2 */
+#define PD67_CHIP_INFO         0x1f    /* Chip information */
+#define PD67_ATA_CTL           0x026   /* 6730: ATA control */
+#define PD67_EXT_INDEX         0x2e    /* Extension index */
+#define PD67_EXT_DATA          0x2f    /* Extension data */
+
+/* PD6722 extension registers -- indexed in PD67_EXT_INDEX */
+#define PD67_DATA_MASK0                0x01    /* Data mask 0 */
+#define PD67_DATA_MASK1                0x02    /* Data mask 1 */
+#define PD67_DMA_CTL           0x03    /* DMA control */
+
+/* PD6730 extension registers -- indexed in PD67_EXT_INDEX */
+#define PD67_EXT_CTL_1         0x03    /* Extension control 1 */
+#define PD67_MEM_PAGE(n)       ((n)+5) /* PCI window bits 31:24 */
+#define PD67_EXTERN_DATA       0x0a
+#define PD67_MISC_CTL_3                0x25
+#define PD67_SMB_PWR_CTL       0x26
+
+/* I/O window address offset */
+#define PD67_IO_OFF(w)         (0x36+((w)<<1))
+
+/* Timing register sets */
+#define PD67_TIME_SETUP(n)     (0x3a + 3*(n))
+#define PD67_TIME_CMD(n)       (0x3b + 3*(n))
+#define PD67_TIME_RECOV(n)     (0x3c + 3*(n))
+
+/* Flags for PD67_MISC_CTL_1 */
+#define PD67_MC1_5V_DET                0x01    /* 5v detect */
+#define PD67_MC1_MEDIA_ENA     0x01    /* 6730: Multimedia enable */
+#define PD67_MC1_VCC_3V                0x02    /* 3.3v Vcc */
+#define PD67_MC1_PULSE_MGMT    0x04
+#define PD67_MC1_PULSE_IRQ     0x08
+#define PD67_MC1_SPKR_ENA      0x10
+#define PD67_MC1_INPACK_ENA    0x80
+
+/* Flags for PD67_FIFO_CTL */
+#define PD67_FIFO_EMPTY                0x80
+
+/* Flags for PD67_MISC_CTL_2 */
+#define PD67_MC2_FREQ_BYPASS   0x01
+#define PD67_MC2_DYNAMIC_MODE  0x02
+#define PD67_MC2_SUSPEND       0x04
+#define PD67_MC2_5V_CORE       0x08
+#define PD67_MC2_LED_ENA       0x10    /* IRQ 12 is LED enable */
+#define PD67_MC2_FAST_PCI      0x10    /* 6729: PCI bus > 25 MHz */
+#define PD67_MC2_3STATE_BIT7   0x20    /* Floppy change bit */
+#define PD67_MC2_DMA_MODE      0x40
+#define PD67_MC2_IRQ15_RI      0x80    /* IRQ 15 is ring enable */
+
+/* Flags for PD67_CHIP_INFO */
+#define PD67_INFO_SLOTS                0x20    /* 0 = 1 slot, 1 = 2 slots */
+#define PD67_INFO_CHIP_ID      0xc0
+#define PD67_INFO_REV          0x1c
+
+/* Fields in PD67_TIME_* registers */
+#define PD67_TIME_SCALE                0xc0
+#define PD67_TIME_SCALE_1      0x00
+#define PD67_TIME_SCALE_16     0x40
+#define PD67_TIME_SCALE_256    0x80
+#define PD67_TIME_SCALE_4096   0xc0
+#define PD67_TIME_MULT         0x3f
+
+/* Fields in PD67_DMA_CTL */
+#define PD67_DMA_MODE          0xc0
+#define PD67_DMA_OFF           0x00
+#define PD67_DMA_DREQ_INPACK   0x40
+#define PD67_DMA_DREQ_WP       0x80
+#define PD67_DMA_DREQ_BVD2     0xc0
+#define PD67_DMA_PULLUP                0x20    /* Disable socket pullups? */
+
+/* Fields in PD67_EXT_CTL_1 */
+#define PD67_EC1_VCC_PWR_LOCK  0x01
+#define PD67_EC1_AUTO_PWR_CLEAR        0x02
+#define PD67_EC1_LED_ENA       0x04
+#define PD67_EC1_INV_CARD_IRQ  0x08
+#define PD67_EC1_INV_MGMT_IRQ  0x10
+#define PD67_EC1_PULLUP_CTL    0x20
+
+/* Fields in PD67_MISC_CTL_3 */
+#define PD67_MC3_IRQ_MASK      0x03
+#define PD67_MC3_IRQ_PCPCI     0x00
+#define PD67_MC3_IRQ_EXTERN    0x01
+#define PD67_MC3_IRQ_PCIWAY    0x02
+#define PD67_MC3_IRQ_PCI       0x03
+#define PD67_MC3_PWR_MASK      0x0c
+#define PD67_MC3_PWR_SERIAL    0x00
+#define PD67_MC3_PWR_TI2202    0x08
+#define PD67_MC3_PWR_SMB       0x0c
+
+/* Register definitions for Cirrus PD6832 PCI-to-CardBus bridge */
+
+/* PD6832 extension registers -- indexed in PD67_EXT_INDEX */
+#define PD68_EXT_CTL_2                 0x0b
+#define PD68_PCI_SPACE                 0x22
+#define PD68_PCCARD_SPACE              0x23
+#define PD68_WINDOW_TYPE               0x24
+#define PD68_EXT_CSC                   0x2e
+#define PD68_MISC_CTL_4                        0x2f
+#define PD68_MISC_CTL_5                        0x30
+#define PD68_MISC_CTL_6                        0x31
+
+/* Extra flags in PD67_MISC_CTL_3 */
+#define PD68_MC3_HW_SUSP               0x10
+#define PD68_MC3_MM_EXPAND             0x40
+#define PD68_MC3_MM_ARM                        0x80
+
+/* Bridge Control Register */
+#define  PD6832_BCR_MGMT_IRQ_ENA       0x0800
+
+/* Socket Number Register */
+#define PD6832_SOCKET_NUMBER           0x004c  /* 8 bit */
+
+#endif /* _LINUX_CIRRUS_H */
diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c
new file mode 100644 (file)
index 0000000..c48feba
--- /dev/null
@@ -0,0 +1,1394 @@
+/*======================================================================
+
+    PCMCIA Card Information Structure parser
+
+    cistpl.c 1.69 1999/08/28 04:01:45
+
+    The contents of this file are subject to the Mozilla Public
+    License Version 1.1 (the "License"); you may not use this file
+    except in compliance with the License. You may obtain a copy of
+    the License at http://www.mozilla.org/MPL/
+
+    Software distributed under the License is distributed on an "AS
+    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+    implied. See the License for the specific language governing
+    rights and limitations under the License.
+
+    The initial developer of the original code is David A. Hinds
+    <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+
+    Alternatively, the contents of this file may be used under the
+    terms of the GNU Public License version 2 (the "GPL"), in which
+    case the provisions of the GPL are applicable instead of the
+    above.  If you wish to allow the use of your version of this file
+    only under the terms of the GPL and not to allow others to use
+    your version of this file under the MPL, indicate your decision
+    by deleting the provisions above and replace them with the notice
+    and other provisions required by the GPL.  If you do not delete
+    the provisions above, a recipient may use your version of this
+    file under either the MPL or the GPL.
+    
+======================================================================*/
+
+#define __NO_VERSION__
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/timer.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/bus_ops.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/bulkmem.h>
+#include <pcmcia/cistpl.h>
+#include "cs_internal.h"
+#include "rsrc_mgr.h"
+
+#define MIN(a, b)              (((a) < (b)) ? (a) : (b))
+
+static const u_char mantissa[] = {
+    10, 12, 13, 15, 20, 25, 30, 35,
+    40, 45, 50, 55, 60, 70, 80, 90
+};
+
+static const u_int exponent[] = {
+    1, 10, 100, 1000, 10000, 100000, 1000000, 10000000
+};
+
+/* Convert an extended speed byte to a time in nanoseconds */
+#define SPEED_CVT(v) \
+    (mantissa[(((v)>>3)&15)-1] * exponent[(v)&7] / 10)
+/* Convert a power byte to a current in 0.1 microamps */
+#define POWER_CVT(v) \
+    (mantissa[((v)>>3)&15] * exponent[(v)&7] / 10)
+#define POWER_SCALE(v)         (exponent[(v)&7])
+
+/* Upper limit on reasonable # of tuples */
+#define MAX_TUPLES             200
+
+/*======================================================================
+
+    Low-level functions to read and write CIS memory.  I think the
+    write routine is only useful for writing one-byte registers.
+    
+======================================================================*/
+
+void read_cis_mem(socket_info_t *s, int attr, u_int addr,
+                 u_int len, void *ptr)
+{
+    pccard_mem_map *mem = &s->cis_mem;
+    u_char *sys;
+    u_int inc = 1;
+    
+    DEBUG(3, ("cs: read_cis_mem(%d, %#x, %u)\n", attr, addr, len));
+    if (setup_cis_mem(s) != 0) {
+       memset(ptr, 0xff, len);
+       return;
+    }
+    mem->flags |= MAP_ACTIVE; mem->flags &= ~MAP_ATTRIB;
+    if (attr) { mem->flags |= MAP_ATTRIB; inc++; addr *= 2; }
+    sys = s->cis_virt + (addr & (s->cap.map_size-1));
+    mem->card_start = addr & ~(s->cap.map_size-1);
+
+    for (; len > 0; sys = s->cis_virt) {
+       s->ss_entry(s->sock, SS_SetMemMap, mem);
+       DEBUG(3,  ("cs:  %#2.2x %#2.2x %#2.2x %#2.2x %#2.2x ...\n",
+                  bus_readb(s->cap.bus, sys),
+                  bus_readb(s->cap.bus, sys+inc),
+                  bus_readb(s->cap.bus, sys+2*inc),
+                  bus_readb(s->cap.bus, sys+3*inc),
+                  bus_readb(s->cap.bus, sys+4*inc)));
+       for ( ; len > 0; len--, ((u_char *)ptr)++, sys += inc) {
+           if (sys == s->cis_virt+s->cap.map_size) break;
+           *(u_char *)ptr = bus_readb(s->cap.bus, sys);
+       }
+       mem->card_start += s->cap.map_size;
+    }
+}
+
+void write_cis_mem(socket_info_t *s, int attr, u_int addr,
+                  u_int len, void *ptr)
+{
+    pccard_mem_map *mem = &s->cis_mem;
+    u_char *sys;
+    int inc = 1;
+    
+    DEBUG(3, ("cs: write_cis_mem(%d, %#x, %u)\n", attr, addr, len));
+    if (setup_cis_mem(s) != 0) return;
+    mem->flags &= ~MAP_ATTRIB;
+    if (attr) { mem->flags |= MAP_ATTRIB; inc++; addr *= 2; }
+    sys = s->cis_virt + (addr & (s->cap.map_size-1));
+    mem->card_start = addr & ~(s->cap.map_size-1);
+    
+    for (; len > 0; sys = s->cis_virt) {
+       s->ss_entry(s->sock, SS_SetMemMap, mem);
+       for ( ; len > 0; len--, ((u_char *)ptr)++, sys += inc) {
+           if (sys == s->cis_virt+s->cap.map_size) break;
+           bus_writeb(s->cap.bus, *(u_char *)ptr, sys);
+       }
+       mem->card_start += s->cap.map_size;
+    }
+}
+
+/*======================================================================
+
+    This is tricky... when we set up CIS memory, we try to validate
+    the memory window space allocations.
+    
+======================================================================*/
+
+/* Scratch pointer to the socket we use for validation */
+static socket_info_t *vs = NULL;
+
+/* Validation function for cards with a valid CIS */
+static int cis_readable(u_long base)
+{
+    cisinfo_t info1, info2;
+    int ret;
+    vs->cis_mem.sys_start = base;
+    vs->cis_mem.sys_stop = base+vs->cap.map_size-1;
+    vs->cis_virt = bus_ioremap(vs->cap.bus, base, vs->cap.map_size);
+    ret = validate_cis(vs->clients, &info1);
+    /* invalidate mapping and CIS cache */
+    bus_iounmap(vs->cap.bus, vs->cis_virt); vs->cis_used = 0;
+    if ((ret != 0) || (info1.Chains == 0))
+       return 0;
+    vs->cis_mem.sys_start = base+vs->cap.map_size;
+    vs->cis_mem.sys_stop = base+2*vs->cap.map_size-1;
+    vs->cis_virt = bus_ioremap(vs->cap.bus, base+vs->cap.map_size,
+                              vs->cap.map_size);
+    ret = validate_cis(vs->clients, &info2);
+    bus_iounmap(vs->cap.bus, vs->cis_virt); vs->cis_used = 0;
+    return ((ret == 0) && (info1.Chains == info2.Chains));
+}
+
+/* Validation function for simple memory cards */
+static int checksum(u_long base)
+{
+    int i, a, b, d;
+    vs->cis_mem.sys_start = base;
+    vs->cis_mem.sys_stop = base+vs->cap.map_size-1;
+    vs->cis_virt = bus_ioremap(vs->cap.bus, base, vs->cap.map_size);
+    vs->cis_mem.card_start = 0;
+    vs->cis_mem.flags = MAP_ACTIVE;
+    vs->ss_entry(vs->sock, SS_SetMemMap, &vs->cis_mem);
+    /* Don't bother checking every word... */
+    a = 0; b = -1;
+    for (i = 0; i < vs->cap.map_size; i += 44) {
+       d = bus_readl(vs->cap.bus, vs->cis_virt+i);
+       a += d; b &= d;
+    }
+    bus_iounmap(vs->cap.bus, vs->cis_virt);
+    return (b == -1) ? -1 : (a>>1);
+}
+
+static int checksum_match(u_long base)
+{
+    int a = checksum(base), b = checksum(base+vs->cap.map_size);
+    return ((a == b) && (a >= 0));
+}
+
+int setup_cis_mem(socket_info_t *s)
+{
+    if (s->cis_mem.sys_start == 0) {
+       int low = !(s->cap.features & SS_CAP_PAGE_REGS);
+       vs = s;
+       validate_mem(cis_readable, checksum_match, low);
+       s->cis_mem.sys_start = 0;
+       vs = NULL;
+       if (find_mem_region(&s->cis_mem.sys_start, s->cap.map_size,
+                           "card services", s->cap.map_size, low)) {
+           printk(KERN_NOTICE "cs: unable to map card memory!\n");
+           return CS_OUT_OF_RESOURCE;
+       }
+       s->cis_mem.sys_stop = s->cis_mem.sys_start+s->cap.map_size-1;
+       s->cis_mem.flags |= MAP_ACTIVE;
+       s->cis_virt = bus_ioremap(s->cap.bus, s->cis_mem.sys_start,
+                                 s->cap.map_size);
+    }
+    return 0;
+}
+
+void release_cis_mem(socket_info_t *s)
+{
+    if (s->cis_mem.sys_start != 0) {
+       s->cis_mem.flags &= ~MAP_ACTIVE;
+       s->ss_entry(s->sock, SS_SetMemMap, &s->cis_mem);
+       release_mem_region(s->cis_mem.sys_start, s->cap.map_size);
+       bus_iounmap(s->cap.bus, s->cis_virt);
+       s->cis_mem.sys_start = 0;
+    }
+}
+
+/*======================================================================
+
+    This is a wrapper around read_cis_mem, with the same interface,
+    but which caches information, for cards whose CIS may not be
+    readable all the time.
+    
+======================================================================*/
+
+static void read_cis_cache(socket_info_t *s, int attr, u_int addr,
+                          u_int len, void *ptr)
+{
+    int i;
+    char *caddr;
+
+    if (s->fake_cis) {
+       if (s->fake_cis_len > addr+len)
+           memcpy(ptr, s->fake_cis+addr, len);
+       else
+           memset(ptr, 0xff, len);
+       return;
+    }
+    caddr = s->cis_cache;
+    for (i = 0; i < s->cis_used; i++) {
+       if ((s->cis_table[i].addr == addr) &&
+           (s->cis_table[i].len == len) &&
+           (s->cis_table[i].attr == attr)) break;
+       caddr += s->cis_table[i].len;
+    }
+    if (i < s->cis_used) {
+       memcpy(ptr, caddr, len);
+       return;
+    }
+#ifdef CONFIG_CARDBUS
+    if (s->state & SOCKET_CARDBUS)
+       read_cb_mem(s, 0, attr, addr, len, ptr);
+    else
+#endif
+       read_cis_mem(s, attr, addr, len, ptr);
+    /* Copy data into the cache, if there is room */
+    if ((i < MAX_CIS_TABLE) &&
+       (caddr+len < s->cis_cache+MAX_CIS_DATA)) {
+       s->cis_table[i].addr = addr;
+       s->cis_table[i].len = len;
+       s->cis_table[i].attr = attr;
+       s->cis_used++;
+       memcpy(caddr, ptr, len);
+    }      
+}
+
+/*======================================================================
+
+    This verifies if the CIS of a card matches what is in the CIS
+    cache.
+    
+======================================================================*/
+
+int verify_cis_cache(socket_info_t *s)
+{
+    char buf[256], *caddr;
+    int i;
+    
+    caddr = s->cis_cache;
+    for (i = 0; i < s->cis_used; i++) {
+#ifdef CONFIG_CARDBUS
+       if (s->state & SOCKET_CARDBUS)
+           read_cb_mem(s, 0, s->cis_table[i].attr, s->cis_table[i].addr,
+                       s->cis_table[i].len, buf);
+       else
+#endif
+           read_cis_mem(s, s->cis_table[i].attr, s->cis_table[i].addr,
+                        s->cis_table[i].len, buf);
+       if (memcmp(buf, caddr, s->cis_table[i].len) != 0)
+           break;
+       caddr += s->cis_table[i].len;
+    }
+    return (i < s->cis_used);
+}
+
+/*======================================================================
+
+    For really bad cards, we provide a facility for uploading a
+    replacement CIS.
+    
+======================================================================*/
+
+int replace_cis(client_handle_t handle, cisdump_t *cis)
+{
+    socket_info_t *s;
+    if (CHECK_HANDLE(handle))
+       return CS_BAD_HANDLE;
+    s = SOCKET(handle);
+    if (s->fake_cis != NULL) {
+       kfree(s->fake_cis);
+       s->fake_cis = NULL;
+    }
+    if (cis->Length > CISTPL_MAX_CIS_SIZE)
+       return CS_BAD_SIZE;
+    s->fake_cis = kmalloc(cis->Length, GFP_KERNEL);
+    if (s->fake_cis == NULL)
+       return CS_OUT_OF_RESOURCE;
+    s->fake_cis_len = cis->Length;
+    memcpy(s->fake_cis, cis->Data, cis->Length);
+    return CS_SUCCESS;
+}
+
+/*======================================================================
+
+    The high-level CIS tuple services
+    
+======================================================================*/
+
+typedef struct tuple_flags {
+    u_int              link_space:3;
+    u_int              has_link:1;
+    u_int              mfc_fn:3;
+    u_int              space:3;
+} tuple_flags;
+
+#define LINK_SPACE(f)  (((tuple_flags *)(&(f)))->link_space)
+#define HAS_LINK(f)    (((tuple_flags *)(&(f)))->has_link)
+#define MFC_FN(f)      (((tuple_flags *)(&(f)))->mfc_fn)
+#define SPACE(f)       (((tuple_flags *)(&(f)))->space)
+
+int get_next_tuple(client_handle_t handle, tuple_t *tuple);
+
+int get_first_tuple(client_handle_t handle, tuple_t *tuple)
+{
+    socket_info_t *s;
+    if (CHECK_HANDLE(handle))
+       return CS_BAD_HANDLE;
+    s = SOCKET(handle);
+    if (!(s->state & SOCKET_PRESENT))
+       return CS_NO_CARD;
+    tuple->TupleLink = tuple->Flags = 0;
+#ifdef CONFIG_CARDBUS
+    if (s->state & SOCKET_CARDBUS) {
+       u_int ptr;
+       pcibios_read_config_dword(s->cap.cardbus, 0, 0x28, &ptr);
+       tuple->CISOffset = ptr & ~7;
+       SPACE(tuple->Flags) = (ptr & 7);
+    } else
+#endif
+    {
+       /* Assume presence of a LONGLINK_C to address 0 */
+       tuple->CISOffset = tuple->LinkOffset = 0;
+       SPACE(tuple->Flags) = HAS_LINK(tuple->Flags) = 1;
+    }
+    if (!(s->state & SOCKET_CARDBUS) && (s->functions > 1) &&
+       !(tuple->Attributes & TUPLE_RETURN_COMMON)) {
+       cisdata_t req = tuple->DesiredTuple;
+       tuple->DesiredTuple = CISTPL_LONGLINK_MFC;
+       if (get_next_tuple(handle, tuple) == CS_SUCCESS) {
+           tuple->DesiredTuple = CISTPL_LINKTARGET;
+           if (get_next_tuple(handle, tuple) != CS_SUCCESS)
+               return CS_NO_MORE_ITEMS;
+       } else
+           tuple->CISOffset = tuple->TupleLink = 0;
+       tuple->DesiredTuple = req;
+    }
+    return get_next_tuple(handle, tuple);
+}
+
+static int follow_link(socket_info_t *s, tuple_t *tuple)
+{
+    u_char link[5];
+    u_int ofs;
+
+    if (MFC_FN(tuple->Flags)) {
+       /* Get indirect link from the MFC tuple */
+       read_cis_cache(s, LINK_SPACE(tuple->Flags),
+                      tuple->LinkOffset, 5, link);
+       ofs = le32_to_cpu(*(u_int *)(link+1));
+       SPACE(tuple->Flags) = (link[0] == CISTPL_MFC_ATTR);
+       /* Move to the next indirect link */
+       tuple->LinkOffset += 5;
+       MFC_FN(tuple->Flags)--;
+    } else if (HAS_LINK(tuple->Flags)) {
+       ofs = tuple->LinkOffset;
+       SPACE(tuple->Flags) = LINK_SPACE(tuple->Flags);
+       HAS_LINK(tuple->Flags) = 0;
+    } else {
+       return -1;
+    }
+    if (!(s->state & SOCKET_CARDBUS) && SPACE(tuple->Flags)) {
+       /* This is ugly, but a common CIS error is to code the long
+          link offset incorrectly, so we check the right spot... */
+       read_cis_cache(s, SPACE(tuple->Flags), ofs, 5, link);
+       if ((link[0] == CISTPL_LINKTARGET) && (link[1] >= 3) &&
+           (strncmp(link+2, "CIS", 3) == 0))
+           return ofs;
+       /* Then, we try the wrong spot... */
+       ofs = ofs >> 1;
+    }
+    read_cis_cache(s, SPACE(tuple->Flags), ofs, 5, link);
+    if ((link[0] != CISTPL_LINKTARGET) || (link[1] < 3) ||
+       (strncmp(link+2, "CIS", 3) != 0))
+       return -1;
+    return ofs;
+}
+
+int get_next_tuple(client_handle_t handle, tuple_t *tuple)
+{
+    socket_info_t *s;
+    u_char link[2], tmp;
+    int ofs, i, attr;
+    
+    if (CHECK_HANDLE(handle))
+       return CS_BAD_HANDLE;
+    s = SOCKET(handle);
+    if (!(s->state & SOCKET_PRESENT))
+       return CS_NO_CARD;
+
+    link[1] = tuple->TupleLink;
+    ofs = tuple->CISOffset + tuple->TupleLink;
+    attr = SPACE(tuple->Flags);
+
+    for (i = 0; i < MAX_TUPLES; i++) {
+       if (link[1] == 0xff) {
+           link[0] = CISTPL_END;
+       } else {
+           read_cis_cache(s, attr, ofs, 2, link);
+           if (link[0] == CISTPL_NULL) {
+               ofs++; continue;
+           }
+       }
+       
+       /* End of chain?  Follow long link if possible */
+       if (link[0] == CISTPL_END) {
+           if ((ofs = follow_link(s, tuple)) < 0)
+               return CS_NO_MORE_ITEMS;
+           attr = SPACE(tuple->Flags);
+           read_cis_cache(s, attr, ofs, 2, link);
+       }
+
+       /* Is this a link tuple?  Make a note of it */
+       if ((link[0] == CISTPL_LONGLINK_A) ||
+           (link[0] == CISTPL_LONGLINK_C) ||
+           (link[0] == CISTPL_LONGLINK_MFC) ||
+           (link[0] == CISTPL_LINKTARGET) ||
+           (link[0] == CISTPL_NO_LINK)) {
+           switch (link[0]) {
+           case CISTPL_LONGLINK_A:
+               HAS_LINK(tuple->Flags) = 1;
+               LINK_SPACE(tuple->Flags) = 1;
+               read_cis_cache(s, attr, ofs+2, 4, &tuple->LinkOffset);
+               break;
+           case CISTPL_LONGLINK_C:
+               HAS_LINK(tuple->Flags) = 1;
+               LINK_SPACE(tuple->Flags) = 0;
+               read_cis_cache(s, attr, ofs+2, 4, &tuple->LinkOffset);
+               break;
+           case CISTPL_LONGLINK_MFC:
+               tuple->LinkOffset = ofs + 3;
+               LINK_SPACE(tuple->Flags) = attr;
+               if (handle->Function == BIND_FN_ALL) {
+                   /* Follow all the MFC links */
+                   read_cis_cache(s, attr, ofs+2, 1, &tmp);
+                   MFC_FN(tuple->Flags) = tmp;
+               } else {
+                   /* Follow exactly one of the links */
+                   MFC_FN(tuple->Flags) = 1;
+                   tuple->LinkOffset += handle->Function * 5;
+               }
+               break;
+           case CISTPL_NO_LINK:
+               HAS_LINK(tuple->Flags) = 0;
+               break;
+           }
+           if ((tuple->Attributes & TUPLE_RETURN_LINK) &&
+               (tuple->DesiredTuple == RETURN_FIRST_TUPLE))
+               break;
+       } else
+           if (tuple->DesiredTuple == RETURN_FIRST_TUPLE)
+               break;
+       
+       if (link[0] == tuple->DesiredTuple)
+           break;
+       ofs += link[1] + 2;
+    }
+    if (i == MAX_TUPLES) {
+       DEBUG(1, ("cs: overrun in get_next_tuple for socket %d\n",
+                 handle->Socket));
+       return CS_NO_MORE_ITEMS;
+    }
+    
+    tuple->TupleCode = link[0];
+    tuple->TupleLink = link[1];
+    tuple->CISOffset = ofs + 2;
+    return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+int get_tuple_data(client_handle_t handle, tuple_t *tuple)
+{
+    socket_info_t *s;
+    u_int len;
+    
+    if (CHECK_HANDLE(handle))
+       return CS_BAD_HANDLE;
+
+    s = SOCKET(handle);
+
+    if (tuple->TupleLink < tuple->TupleOffset)
+       return CS_NO_MORE_ITEMS;
+    len = tuple->TupleLink - tuple->TupleOffset;
+    tuple->TupleDataLen = tuple->TupleLink;
+    if (len == 0)
+       return CS_SUCCESS;
+    read_cis_cache(s, SPACE(tuple->Flags),
+                  tuple->CISOffset + tuple->TupleOffset,
+                  MIN(len, tuple->TupleDataMax), tuple->TupleData);
+    return CS_SUCCESS;
+}
+
+/*======================================================================
+
+    Parsing routines for individual tuples
+    
+======================================================================*/
+
+static int parse_device(tuple_t *tuple, cistpl_device_t *device)
+{
+    int i;
+    u_char scale;
+    u_char *p, *q;
+
+    p = (u_char *)tuple->TupleData;
+    q = p + tuple->TupleDataLen;
+
+    device->ndev = 0;
+    for (i = 0; i < CISTPL_MAX_DEVICES; i++) {
+       
+       if (*p == 0xff) break;
+       device->dev[i].type = (*p >> 4);
+       device->dev[i].wp = (*p & 0x08) ? 1 : 0;
+       switch (*p & 0x07) {
+       case 0: device->dev[i].speed = 0;   break;
+       case 1: device->dev[i].speed = 250; break;
+       case 2: device->dev[i].speed = 200; break;
+       case 3: device->dev[i].speed = 150; break;
+       case 4: device->dev[i].speed = 100; break;
+       case 7:
+           if (++p == q) return CS_BAD_TUPLE;
+           if (p == q)
+               return CS_BAD_TUPLE;
+           device->dev[i].speed = SPEED_CVT(*p);
+           while (*p & 0x80)
+               if (++p == q) return CS_BAD_TUPLE;
+           break;
+       default:
+           return CS_BAD_TUPLE;
+       }
+
+       if (++p == q) return CS_BAD_TUPLE;
+       if (*p == 0xff) break;
+       scale = *p & 7;
+       if (scale == 7) return CS_BAD_TUPLE;
+       device->dev[i].size = ((*p >> 3) + 1) * (512 << (scale*2));
+       device->ndev++;
+       if (++p == q) break;
+    }
+    
+    return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+static int parse_checksum(tuple_t *tuple, cistpl_checksum_t *csum)
+{
+    u_char *p;
+    if (tuple->TupleDataLen < 5)
+       return CS_BAD_TUPLE;
+    p = (u_char *)tuple->TupleData;
+    csum->addr = tuple->CISOffset+(short)le16_to_cpu(*(u_short *)p)-2;
+    csum->len = le16_to_cpu(*(u_short *)(p + 2));
+    csum->sum = *(p+4);
+    return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+static int parse_longlink(tuple_t *tuple, cistpl_longlink_t *link)
+{
+    if (tuple->TupleDataLen < 4)
+       return CS_BAD_TUPLE;
+    link->addr = le32_to_cpu(*(u_int *)tuple->TupleData);
+    return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+static int parse_longlink_mfc(tuple_t *tuple,
+                             cistpl_longlink_mfc_t *link)
+{
+    u_char *p;
+    int i;
+    
+    p = (u_char *)tuple->TupleData;
+    
+    link->nfn = *p; p++;
+    if (tuple->TupleDataLen <= link->nfn*5)
+       return CS_BAD_TUPLE;
+    for (i = 0; i < link->nfn; i++) {
+       link->fn[i].space = *p; p++;
+       link->fn[i].addr = le32_to_cpu(*(u_int *)p); p += 4;
+    }
+    return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+static int parse_strings(u_char *p, u_char *q, int max,
+                        char *s, u_char *ofs, u_char *found)
+{
+    int i, j, ns;
+
+    if (p == q) return CS_BAD_TUPLE;
+    ns = 0; j = 0;
+    for (i = 0; i < max; i++) {
+       if (*p == 0xff) break;
+       ofs[i] = j;
+       ns++;
+       for (;;) {
+           s[j++] = (*p == 0xff) ? '\0' : *p;
+           if ((*p == '\0') || (*p == 0xff)) break;
+           if (++p == q) return CS_BAD_TUPLE;
+       }
+       if ((*p == 0xff) || (++p == q)) break;
+    }
+    if (found) {
+       *found = ns;
+       return CS_SUCCESS;
+    } else {
+       return (ns == max) ? CS_SUCCESS : CS_BAD_TUPLE;
+    }
+}
+
+/*====================================================================*/
+
+static int parse_vers_1(tuple_t *tuple, cistpl_vers_1_t *vers_1)
+{
+    u_char *p, *q;
+    
+    p = (u_char *)tuple->TupleData;
+    q = p + tuple->TupleDataLen;
+    
+    vers_1->major = *p; p++;
+    vers_1->minor = *p; p++;
+    if (p >= q) return CS_BAD_TUPLE;
+
+    return parse_strings(p, q, CISTPL_VERS_1_MAX_PROD_STRINGS,
+                        vers_1->str, vers_1->ofs, &vers_1->ns);
+}
+
+/*====================================================================*/
+
+static int parse_altstr(tuple_t *tuple, cistpl_altstr_t *altstr)
+{
+    u_char *p, *q;
+    
+    p = (u_char *)tuple->TupleData;
+    q = p + tuple->TupleDataLen;
+    
+    return parse_strings(p, q, CISTPL_MAX_ALTSTR_STRINGS,
+                        altstr->str, altstr->ofs, &altstr->ns);
+}
+
+/*====================================================================*/
+
+static int parse_jedec(tuple_t *tuple, cistpl_jedec_t *jedec)
+{
+    u_char *p, *q;
+    int nid;
+
+    p = (u_char *)tuple->TupleData;
+    q = p + tuple->TupleDataLen;
+
+    for (nid = 0; nid < CISTPL_MAX_DEVICES; nid++) {
+       if (p > q-2) break;
+       jedec->id[nid].mfr = p[0];
+       jedec->id[nid].info = p[1];
+       p += 2;
+    }
+    jedec->nid = nid;
+    return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+static int parse_manfid(tuple_t *tuple, cistpl_manfid_t *m)
+{
+    u_short *p;
+    if (tuple->TupleDataLen < 4)
+       return CS_BAD_TUPLE;
+    p = (u_short *)tuple->TupleData;
+    m->manf = le16_to_cpu(p[0]);
+    m->card = le16_to_cpu(p[1]);
+    return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+static int parse_funcid(tuple_t *tuple, cistpl_funcid_t *f)
+{
+    u_char *p;
+    if (tuple->TupleDataLen < 2)
+       return CS_BAD_TUPLE;
+    p = (u_char *)tuple->TupleData;
+    f->func = p[0];
+    f->sysinit = p[1];
+    return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+static int parse_funce(tuple_t *tuple, cistpl_funce_t *f)
+{
+    u_char *p;
+    int i;
+    if (tuple->TupleDataLen < 1)
+       return CS_BAD_TUPLE;
+    p = (u_char *)tuple->TupleData;
+    f->type = p[0];
+    for (i = 1; i < tuple->TupleDataLen; i++)
+       f->data[i-1] = p[i];
+    return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+static int parse_config(tuple_t *tuple, cistpl_config_t *config)
+{
+    int rasz, rmsz, i;
+    u_char *p;
+
+    p = (u_char *)tuple->TupleData;
+    rasz = *p & 0x03;
+    rmsz = (*p & 0x3c) >> 2;
+    if (tuple->TupleDataLen < rasz+rmsz+4)
+       return CS_BAD_TUPLE;
+    config->last_idx = *(++p);
+    p++;
+    config->base = 0;
+    for (i = 0; i <= rasz; i++)
+       config->base += p[i] << (8*i);
+    p += rasz+1;
+    for (i = 0; i < 4; i++)
+       config->rmask[i] = 0;
+    for (i = 0; i <= rmsz; i++)
+       config->rmask[i>>2] += p[i] << (8*(i%4));
+    config->subtuples = tuple->TupleDataLen - (rasz+rmsz+4);
+    return CS_SUCCESS;
+}
+
+/*======================================================================
+
+    The following routines are all used to parse the nightmarish
+    config table entries.
+    
+======================================================================*/
+
+static u_char *parse_power(u_char *p, u_char *q,
+                          cistpl_power_t *pwr)
+{
+    int i;
+    u_int scale;
+
+    if (p == q) return NULL;
+    pwr->present = *p;
+    pwr->flags = 0;
+    p++;
+    for (i = 0; i < 7; i++)
+       if (pwr->present & (1<<i)) {
+           if (p == q) return NULL;
+           pwr->param[i] = POWER_CVT(*p);
+           scale = POWER_SCALE(*p);
+           while (*p & 0x80) {
+               if (++p == q) return NULL;
+               if ((*p & 0x7f) < 100)
+                   pwr->param[i] += (*p & 0x7f) * scale / 100;
+               else if (*p == 0x7d)
+                   pwr->flags |= CISTPL_POWER_HIGHZ_OK;
+               else if (*p == 0x7e)
+                   pwr->param[i] = 0;
+               else if (*p == 0x7f)
+                   pwr->flags |= CISTPL_POWER_HIGHZ_REQ;
+               else
+                   return NULL;
+           }
+           p++;
+       }
+    return p;
+}
+
+/*====================================================================*/
+
+static u_char *parse_timing(u_char *p, u_char *q,
+                           cistpl_timing_t *timing)
+{
+    u_char scale;
+
+    if (p == q) return NULL;
+    scale = *p;
+    if ((scale & 3) != 3) {
+       if (++p == q) return NULL;
+       timing->wait = SPEED_CVT(*p);
+       timing->waitscale = exponent[scale & 3];
+    } else
+       timing->wait = 0;
+    scale >>= 2;
+    if ((scale & 7) != 7) {
+       if (++p == q) return NULL;
+       timing->ready = SPEED_CVT(*p);
+       timing->rdyscale = exponent[scale & 7];
+    } else
+       timing->ready = 0;
+    scale >>= 3;
+    if (scale != 7) {
+       if (++p == q) return NULL;
+       timing->reserved = SPEED_CVT(*p);
+       timing->rsvscale = exponent[scale];
+    } else
+       timing->reserved = 0;
+    p++;
+    return p;
+}
+
+/*====================================================================*/
+
+static u_char *parse_io(u_char *p, u_char *q, cistpl_io_t *io)
+{
+    int i, j, bsz, lsz;
+
+    if (p == q) return NULL;
+    io->flags = *p;
+
+    if (!(*p & 0x80)) {
+       io->nwin = 1;
+       io->win[0].base = 0;
+       io->win[0].len = (1 << (io->flags & CISTPL_IO_LINES_MASK));
+       return p+1;
+    }
+    
+    if (++p == q) return NULL;
+    io->nwin = (*p & 0x0f) + 1;
+    bsz = (*p & 0x30) >> 4;
+    if (bsz == 3) bsz++;
+    lsz = (*p & 0xc0) >> 6;
+    if (lsz == 3) lsz++;
+    p++;
+    
+    for (i = 0; i < io->nwin; i++) {
+       io->win[i].base = 0;
+       io->win[i].len = 1;
+       for (j = 0; j < bsz; j++, p++) {
+           if (p == q) return NULL;
+           io->win[i].base += *p << (j*8);
+       }
+       for (j = 0; j < lsz; j++, p++) {
+           if (p == q) return NULL;
+           io->win[i].len += *p << (j*8);
+       }
+    }
+    return p;
+}
+
+/*====================================================================*/
+
+static u_char *parse_mem(u_char *p, u_char *q, cistpl_mem_t *mem)
+{
+    int i, j, asz, lsz, has_ha;
+    u_int len, ca, ha;
+
+    if (p == q) return NULL;
+
+    mem->nwin = (*p & 0x07) + 1;
+    lsz = (*p & 0x18) >> 3;
+    asz = (*p & 0x60) >> 5;
+    has_ha = (*p & 0x80);
+    if (++p == q) return NULL;
+    
+    for (i = 0; i < mem->nwin; i++) {
+       len = ca = ha = 0;
+       for (j = 0; j < lsz; j++, p++) {
+           if (p == q) return NULL;
+           len += *p << (j*8);
+       }
+       for (j = 0; j < asz; j++, p++) {
+           if (p == q) return NULL;
+           ca += *p << (j*8);
+       }
+       if (has_ha)
+           for (j = 0; j < asz; j++, p++) {
+               if (p == q) return NULL;
+               ha += *p << (j*8);
+           }
+       mem->win[i].len = len << 8;
+       mem->win[i].card_addr = ca << 8;
+       mem->win[i].host_addr = ha << 8;
+    }
+    return p;
+}
+
+/*====================================================================*/
+
+static u_char *parse_irq(u_char *p, u_char *q, cistpl_irq_t *irq)
+{
+    if (p == q) return NULL;
+    irq->IRQInfo1 = *p; p++;
+    if (irq->IRQInfo1 & IRQ_INFO2_VALID) {
+       if (p+2 > q) return NULL;
+       irq->IRQInfo2 = (p[1]<<8) + p[0];
+       p += 2;
+    }
+    return p;
+}
+
+/*====================================================================*/
+
+static int parse_cftable_entry(tuple_t *tuple,
+                              cistpl_cftable_entry_t *entry)
+{
+    u_char *p, *q, features;
+
+    p = tuple->TupleData;
+    q = p + tuple->TupleDataLen;
+    entry->index = *p & 0x3f;
+    entry->flags = 0;
+    if (*p & 0x40)
+       entry->flags |= CISTPL_CFTABLE_DEFAULT;
+    if (*p & 0x80) {
+       if (++p == q) return CS_BAD_TUPLE;
+       if (*p & 0x10)
+           entry->flags |= CISTPL_CFTABLE_BVDS;
+       if (*p & 0x20)
+           entry->flags |= CISTPL_CFTABLE_WP;
+       if (*p & 0x40)
+           entry->flags |= CISTPL_CFTABLE_RDYBSY;
+       if (*p & 0x80)
+           entry->flags |= CISTPL_CFTABLE_MWAIT;
+       entry->interface = *p & 0x0f;
+    } else
+       entry->interface = 0;
+
+    /* Process optional features */
+    if (++p == q) return CS_BAD_TUPLE;
+    features = *p; p++;
+
+    /* Power options */
+    if ((features & 3) > 0) {
+       p = parse_power(p, q, &entry->vcc);
+       if (p == NULL) return CS_BAD_TUPLE;
+    } else
+       entry->vcc.present = 0;
+    if ((features & 3) > 1) {
+       p = parse_power(p, q, &entry->vpp1);
+       if (p == NULL) return CS_BAD_TUPLE;
+    } else
+       entry->vpp1.present = 0;
+    if ((features & 3) > 2) {
+       p = parse_power(p, q, &entry->vpp2);
+       if (p == NULL) return CS_BAD_TUPLE;
+    } else
+       entry->vpp2.present = 0;
+
+    /* Timing options */
+    if (features & 0x04) {
+       p = parse_timing(p, q, &entry->timing);
+       if (p == NULL) return CS_BAD_TUPLE;
+    } else {
+       entry->timing.wait = 0;
+       entry->timing.ready = 0;
+       entry->timing.reserved = 0;
+    }
+    
+    /* I/O window options */
+    if (features & 0x08) {
+       p = parse_io(p, q, &entry->io);
+       if (p == NULL) return CS_BAD_TUPLE;
+    } else
+       entry->io.nwin = 0;
+    
+    /* Interrupt options */
+    if (features & 0x10) {
+       p = parse_irq(p, q, &entry->irq);
+       if (p == NULL) return CS_BAD_TUPLE;
+    } else
+       entry->irq.IRQInfo1 = 0;
+
+    switch (features & 0x60) {
+    case 0x00:
+       entry->mem.nwin = 0;
+       break;
+    case 0x20:
+       entry->mem.nwin = 1;
+       entry->mem.win[0].len = le16_to_cpu(*(u_short *)p) << 8;
+       entry->mem.win[0].card_addr = 0;
+       entry->mem.win[0].host_addr = 0;
+       p += 2;
+       if (p > q) return CS_BAD_TUPLE;
+       break;
+    case 0x40:
+       entry->mem.nwin = 1;
+       entry->mem.win[0].len = le16_to_cpu(*(u_short *)p) << 8;
+       entry->mem.win[0].card_addr =
+           le16_to_cpu(*(u_short *)(p+2)) << 8;
+       entry->mem.win[0].host_addr = 0;
+       p += 4;
+       if (p > q) return CS_BAD_TUPLE;
+       break;
+    case 0x60:
+       p = parse_mem(p, q, &entry->mem);
+       if (p == NULL) return CS_BAD_TUPLE;
+       break;
+    }
+
+    /* Misc features */
+    if (features & 0x80) {
+       if (p == q) return CS_BAD_TUPLE;
+       entry->flags |= (*p << 8);
+       while (*p & 0x80)
+           if (++p == q) return CS_BAD_TUPLE;
+       p++;
+    }
+
+    entry->subtuples = q-p;
+    
+    return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+#ifdef CONFIG_CARDBUS
+
+static int parse_bar(tuple_t *tuple, cistpl_bar_t *bar)
+{
+    u_char *p;
+    if (tuple->TupleDataLen < 6)
+       return CS_BAD_TUPLE;
+    p = (u_char *)tuple->TupleData;
+    bar->attr = *p;
+    p += 2;
+    bar->size = le32_to_cpu(*(u_int *)p);
+    return CS_SUCCESS;
+}
+
+static int parse_config_cb(tuple_t *tuple, cistpl_config_t *config)
+{
+    u_char *p;
+    
+    p = (u_char *)tuple->TupleData;
+    if ((*p != 3) || (tuple->TupleDataLen < 6))
+       return CS_BAD_TUPLE;
+    config->last_idx = *(++p);
+    p++;
+    config->base = le32_to_cpu(*(u_int *)p);
+    config->subtuples = tuple->TupleDataLen - 6;
+    return CS_SUCCESS;
+}
+
+static int parse_cftable_entry_cb(tuple_t *tuple,
+                                 cistpl_cftable_entry_cb_t *entry)
+{
+    u_char *p, *q, features;
+
+    p = tuple->TupleData;
+    q = p + tuple->TupleDataLen;
+    entry->index = *p & 0x3f;
+    entry->flags = 0;
+    if (*p & 0x40)
+       entry->flags |= CISTPL_CFTABLE_DEFAULT;
+
+    /* Process optional features */
+    if (++p == q) return CS_BAD_TUPLE;
+    features = *p; p++;
+
+    /* Power options */
+    if ((features & 3) > 0) {
+       p = parse_power(p, q, &entry->vcc);
+       if (p == NULL) return CS_BAD_TUPLE;
+    } else
+       entry->vcc.present = 0;
+    if ((features & 3) > 1) {
+       p = parse_power(p, q, &entry->vpp1);
+       if (p == NULL) return CS_BAD_TUPLE;
+    } else
+       entry->vpp1.present = 0;
+    if ((features & 3) > 2) {
+       p = parse_power(p, q, &entry->vpp2);
+       if (p == NULL) return CS_BAD_TUPLE;
+    } else
+       entry->vpp2.present = 0;
+
+    /* I/O window options */
+    if (features & 0x08) {
+       if (p == q) return CS_BAD_TUPLE;
+       entry->io = *p; p++;
+    } else
+       entry->io = 0;
+    
+    /* Interrupt options */
+    if (features & 0x10) {
+       p = parse_irq(p, q, &entry->irq);
+       if (p == NULL) return CS_BAD_TUPLE;
+    } else
+       entry->irq.IRQInfo1 = 0;
+
+    if (features & 0x20) {
+       if (p == q) return CS_BAD_TUPLE;
+       entry->mem = *p; p++;
+    } else
+       entry->mem = 0;
+
+    /* Misc features */
+    if (features & 0x80) {
+       if (p == q) return CS_BAD_TUPLE;
+       entry->flags |= (*p << 8);
+       if (*p & 0x80) {
+           if (++p == q) return CS_BAD_TUPLE;
+           entry->flags |= (*p << 16);
+       }
+       while (*p & 0x80)
+           if (++p == q) return CS_BAD_TUPLE;
+       p++;
+    }
+
+    entry->subtuples = q-p;
+    
+    return CS_SUCCESS;
+}
+
+#endif
+
+/*====================================================================*/
+
+static int parse_device_geo(tuple_t *tuple, cistpl_device_geo_t *geo)
+{
+    u_char *p, *q;
+    int n;
+
+    p = (u_char *)tuple->TupleData;
+    q = p + tuple->TupleDataLen;
+
+    for (n = 0; n < CISTPL_MAX_DEVICES; n++) {
+       if (p > q-6) break;
+       geo->geo[n].buswidth = p[0];
+       geo->geo[n].erase_block = 1 << (p[1]-1);
+       geo->geo[n].read_block  = 1 << (p[2]-1);
+       geo->geo[n].write_block = 1 << (p[3]-1);
+       geo->geo[n].partition   = 1 << (p[4]-1);
+       geo->geo[n].interleave  = 1 << (p[5]-1);
+       p += 6;
+    }
+    geo->ngeo = n;
+    return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+static int parse_vers_2(tuple_t *tuple, cistpl_vers_2_t *v2)
+{
+    u_char *p, *q;
+
+    if (tuple->TupleDataLen < 10)
+       return CS_BAD_TUPLE;
+    
+    p = tuple->TupleData;
+    q = p + tuple->TupleDataLen;
+
+    v2->vers = p[0];
+    v2->comply = p[1];
+    v2->dindex = le16_to_cpu(*(u_short *)(p+2));
+    v2->vspec8 = p[6];
+    v2->vspec9 = p[7];
+    v2->nhdr = p[8];
+    p += 9;
+    return parse_strings(p, q, 2, v2->str, &v2->vendor, NULL);
+}
+
+/*====================================================================*/
+
+static int parse_org(tuple_t *tuple, cistpl_org_t *org)
+{
+    u_char *p, *q;
+    int i;
+    
+    p = tuple->TupleData;
+    q = p + tuple->TupleDataLen;
+    if (p == q) return CS_BAD_TUPLE;
+    org->data_org = *p;
+    if (++p == q) return CS_BAD_TUPLE;
+    for (i = 0; i < 30; i++) {
+       org->desc[i] = *p;
+       if (*p == '\0') break;
+       if (++p == q) return CS_BAD_TUPLE;
+    }
+    return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+int parse_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
+{
+    int ret = CS_SUCCESS;
+    
+    if (tuple->TupleDataLen > tuple->TupleDataMax)
+       return CS_BAD_TUPLE;
+    switch (tuple->TupleCode) {
+    case CISTPL_DEVICE:
+    case CISTPL_DEVICE_A:
+       ret = parse_device(tuple, &parse->device);
+       break;
+#ifdef CONFIG_CARDBUS
+    case CISTPL_BAR:
+       ret = parse_bar(tuple, &parse->bar);
+       break;
+    case CISTPL_CONFIG_CB:
+       ret = parse_config_cb(tuple, &parse->config);
+       break;
+    case CISTPL_CFTABLE_ENTRY_CB:
+       ret = parse_cftable_entry_cb(tuple, &parse->cftable_entry_cb);
+       break;
+#endif
+    case CISTPL_CHECKSUM:
+       ret = parse_checksum(tuple, &parse->checksum);
+       break;
+    case CISTPL_LONGLINK_A:
+    case CISTPL_LONGLINK_C:
+       ret = parse_longlink(tuple, &parse->longlink);
+       break;
+    case CISTPL_LONGLINK_MFC:
+       ret = parse_longlink_mfc(tuple, &parse->longlink_mfc);
+       break;
+    case CISTPL_VERS_1:
+       ret = parse_vers_1(tuple, &parse->version_1);
+       break;
+    case CISTPL_ALTSTR:
+       ret = parse_altstr(tuple, &parse->altstr);
+       break;
+    case CISTPL_JEDEC_A:
+    case CISTPL_JEDEC_C:
+       ret = parse_jedec(tuple, &parse->jedec);
+       break;
+    case CISTPL_MANFID:
+       ret = parse_manfid(tuple, &parse->manfid);
+       break;
+    case CISTPL_FUNCID:
+       ret = parse_funcid(tuple, &parse->funcid);
+       break;
+    case CISTPL_FUNCE:
+       ret = parse_funce(tuple, &parse->funce);
+       break;
+    case CISTPL_CONFIG:
+       ret = parse_config(tuple, &parse->config);
+       break;
+    case CISTPL_CFTABLE_ENTRY:
+       ret = parse_cftable_entry(tuple, &parse->cftable_entry);
+       break;
+    case CISTPL_DEVICE_GEO:
+    case CISTPL_DEVICE_GEO_A:
+       ret = parse_device_geo(tuple, &parse->device_geo);
+       break;
+    case CISTPL_VERS_2:
+       ret = parse_vers_2(tuple, &parse->vers_2);
+       break;
+    case CISTPL_ORG:
+       ret = parse_org(tuple, &parse->org);
+       break;
+    case CISTPL_NO_LINK:
+    case CISTPL_LINKTARGET:
+       ret = CS_SUCCESS;
+       break;
+    default:
+       ret = CS_UNSUPPORTED_FUNCTION;
+       break;
+    }
+    return ret;
+}
+
+/*======================================================================
+
+    This is used internally by Card Services to look up CIS stuff.
+    
+======================================================================*/
+
+int read_tuple(client_handle_t handle, cisdata_t code, void *parse)
+{
+    tuple_t tuple;
+    cisdata_t buf[255];
+    int ret;
+    
+    tuple.DesiredTuple = code;
+    tuple.Attributes = TUPLE_RETURN_COMMON;
+    ret = CardServices(GetFirstTuple, handle, &tuple, NULL);
+    if (ret != CS_SUCCESS) return ret;
+    tuple.TupleData = buf;
+    tuple.TupleOffset = 0;
+    tuple.TupleDataMax = sizeof(buf);
+    ret = CardServices(GetTupleData, handle, &tuple, NULL);
+    if (ret != CS_SUCCESS) return ret;
+    ret = CardServices(ParseTuple, handle, &tuple, parse);
+    return ret;
+}
+
+/*======================================================================
+
+    This tries to determine if a card has a sensible CIS.  It returns
+    the number of tuples in the CIS, or 0 if the CIS looks bad.  The
+    checks include making sure several critical tuples are present and
+    valid; seeing if the total number of tuples is reasonable; and
+    looking for tuples that use reserved codes.
+    
+======================================================================*/
+
+int validate_cis(client_handle_t handle, cisinfo_t *info)
+{
+    tuple_t tuple;
+    cisparse_t p;
+    int ret, reserved, errors;
+    
+    if (CHECK_HANDLE(handle))
+       return CS_BAD_HANDLE;
+    
+    info->Chains = reserved = errors = 0;
+    tuple.DesiredTuple = RETURN_FIRST_TUPLE;
+    tuple.Attributes = TUPLE_RETURN_COMMON;
+    ret = get_first_tuple(handle, &tuple);
+    if (ret != CS_SUCCESS)
+       return CS_SUCCESS;
+
+    /* First tuple should be DEVICE */
+    if (tuple.TupleCode != CISTPL_DEVICE)
+       errors++;
+    /* All cards should have a MANFID tuple */
+    if (read_tuple(handle, CISTPL_MANFID, &p) != CS_SUCCESS)
+       errors++;
+    /* All cards should have either a VERS_1 or a VERS_2 tuple.  But
+       at worst, we'll accept a CFTABLE_ENTRY that parses. */
+    if ((read_tuple(handle, CISTPL_VERS_1, &p) != CS_SUCCESS) &&
+       (read_tuple(handle, CISTPL_VERS_2, &p) != CS_SUCCESS) &&
+       (read_tuple(handle, CISTPL_CFTABLE_ENTRY, &p) != CS_SUCCESS) &&
+       (read_tuple(handle, CISTPL_CFTABLE_ENTRY_CB, &p) != CS_SUCCESS))
+       errors++;
+    if (errors > 1)
+       return CS_SUCCESS;
+    
+    for (info->Chains = 1; info->Chains < MAX_TUPLES; info->Chains++) {
+       ret = get_next_tuple(handle, &tuple);
+       if (ret != CS_SUCCESS) break;
+       if (((tuple.TupleCode > 0x23) && (tuple.TupleCode < 0x40)) ||
+           ((tuple.TupleCode > 0x47) && (tuple.TupleCode < 0x80)) ||
+           ((tuple.TupleCode > 0x90) && (tuple.TupleCode < 0xff)))
+           reserved++;
+    }
+    if ((info->Chains == MAX_TUPLES) || (reserved > 5))
+       info->Chains = 0;
+    
+    return CS_SUCCESS;
+}
+
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
new file mode 100644 (file)
index 0000000..0f85fa7
--- /dev/null
@@ -0,0 +1,2188 @@
+/*======================================================================
+
+    PCMCIA Card Services -- core services
+
+    cs.c 1.224 1999/08/28 04:01:45
+    
+    The contents of this file are subject to the Mozilla Public
+    License Version 1.1 (the "License"); you may not use this file
+    except in compliance with the License. You may obtain a copy of
+    the License at http://www.mozilla.org/MPL/
+
+    Software distributed under the License is distributed on an "AS
+    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+    implied. See the License for the specific language governing
+    rights and limitations under the License.
+
+    The initial developer of the original code is David A. Hinds
+    <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+
+    Alternatively, the contents of this file may be used under the
+    terms of the GNU Public License version 2 (the "GPL"), in which
+    case the provisions of the GPL are applicable instead of the
+    above.  If you wish to allow the use of your version of this file
+    only under the terms of the GPL and not to allow others to use
+    your version of this file under the MPL, indicate your decision
+    by deleting the provisions above and replace them with the notice
+    and other provisions required by the GPL.  If you do not delete
+    the provisions above, a recipient may use your version of this
+    file under either the MPL or the GPL.
+    
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/proc_fs.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+
+#define IN_CARD_SERVICES
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/bulkmem.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/bus_ops.h>
+#include "cs_internal.h"
+#include "rsrc_mgr.h"
+
+#ifdef CONFIG_APM
+#include <linux/apm_bios.h>
+static int handle_apm_event(apm_event_t event);
+#endif
+
+#ifdef PCMCIA_DEBUG
+int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+static const char *version =
+"cs.c 1.224 1999/08/28 04:01:45 (David Hinds)";
+#endif
+
+static const char *release = "Linux PCMCIA Card Services " CS_RELEASE;
+
+static const char *options = "options: "
+#ifdef CONFIG_PCI
+" [pci]"
+#endif
+#ifdef CONFIG_CARDBUS
+" [cardbus]"
+#endif
+#ifdef CONFIG_APM
+" [apm]"
+#endif
+#if !defined(CONFIG_CARDBUS) && !defined(CONFIG_PCI) && !defined(CONFIG_APM)
+" none"
+#endif
+;
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+static int setup_delay         = HZ/20;        /* ticks */
+static int resume_delay                = HZ/5;         /* ticks */
+static int shutdown_delay      = HZ/40;        /* ticks */
+static int vcc_settle          = HZ*3/10;      /* ticks */
+static int reset_time          = 10;           /* usecs */
+static int unreset_delay       = HZ/10;        /* ticks */
+static int unreset_check       = HZ/10;        /* ticks */
+static int unreset_limit       = 30;           /* unreset_check's */
+
+/* Access speed for attribute memory windows */
+static int cis_speed           = 300;  /* ns */
+
+/* Access speed for IO windows */
+static int io_speed            = 0;    /* ns */
+
+/* Optional features */
+#ifdef CONFIG_APM
+static int do_apm              = 1;
+MODULE_PARM(do_apm, "i");
+#endif
+
+MODULE_PARM(setup_delay, "i");
+MODULE_PARM(resume_delay, "i");
+MODULE_PARM(shutdown_delay, "i");
+MODULE_PARM(vcc_settle, "i");
+MODULE_PARM(reset_time, "i");
+MODULE_PARM(unreset_delay, "i");
+MODULE_PARM(unreset_check, "i");
+MODULE_PARM(unreset_limit, "i");
+MODULE_PARM(cis_speed, "i");
+MODULE_PARM(io_speed, "i");
+
+/*====================================================================*/
+
+static socket_state_t dead_socket = {
+    0, SS_DETECT, 0, 0, 0
+};
+
+/* Table of sockets */
+socket_t sockets = 0;
+socket_info_t *socket_table[MAX_SOCK];
+
+#ifdef CONFIG_PROC_FS
+struct proc_dir_entry *proc_pccard = NULL;
+#endif
+
+/*====================================================================*/
+
+/* String tables for error messages */
+
+typedef struct lookup_t {
+    int key;
+    char *msg;
+} lookup_t;
+
+static const lookup_t error_table[] = {
+    { CS_SUCCESS,              "Operation succeeded" },
+    { CS_BAD_ADAPTER,          "Bad adapter" },
+    { CS_BAD_ATTRIBUTE,        "Bad attribute", },
+    { CS_BAD_BASE,             "Bad base address" },
+    { CS_BAD_EDC,              "Bad EDC" },
+    { CS_BAD_IRQ,              "Bad IRQ" },
+    { CS_BAD_OFFSET,           "Bad offset" },
+    { CS_BAD_PAGE,             "Bad page number" },
+    { CS_READ_FAILURE,         "Read failure" },
+    { CS_BAD_SIZE,             "Bad size" },
+    { CS_BAD_SOCKET,           "Bad socket" },
+    { CS_BAD_TYPE,             "Bad type" },
+    { CS_BAD_VCC,              "Bad Vcc" },
+    { CS_BAD_VPP,              "Bad Vpp" },
+    { CS_BAD_WINDOW,           "Bad window" },
+    { CS_WRITE_FAILURE,                "Write failure" },
+    { CS_NO_CARD,              "No card present" },
+    { CS_UNSUPPORTED_FUNCTION, "Usupported function" },
+    { CS_UNSUPPORTED_MODE,     "Unsupported mode" },
+    { CS_BAD_SPEED,            "Bad speed" },
+    { CS_BUSY,                 "Resource busy" },
+    { CS_GENERAL_FAILURE,      "General failure" },
+    { CS_WRITE_PROTECTED,      "Write protected" },
+    { CS_BAD_ARG_LENGTH,       "Bad argument length" },
+    { CS_BAD_ARGS,             "Bad arguments" },
+    { CS_CONFIGURATION_LOCKED, "Configuration locked" },
+    { CS_IN_USE,               "Resource in use" },
+    { CS_NO_MORE_ITEMS,                "No more items" },
+    { CS_OUT_OF_RESOURCE,      "Out of resource" },
+    { CS_BAD_HANDLE,           "Bad handle" },
+    { CS_BAD_TUPLE,            "Bad CIS tuple" }
+};
+#define ERROR_COUNT (sizeof(error_table)/sizeof(lookup_t))
+
+static const lookup_t service_table[] = {
+    { AccessConfigurationRegister,     "AccessConfigurationRegister" },
+    { AddSocketServices,               "AddSocketServices" },
+    { AdjustResourceInfo,              "AdjustResourceInfo" },
+    { CheckEraseQueue,                 "CheckEraseQueue" },
+    { CloseMemory,                     "CloseMemory" },
+    { DeregisterClient,                        "DeregisterClient" },
+    { DeregisterEraseQueue,            "DeregisterEraseQueue" },
+    { GetCardServicesInfo,             "GetCardServicesInfo" },
+    { GetClientInfo,                   "GetClientInfo" },
+    { GetConfigurationInfo,            "GetConfigurationInfo" },
+    { GetEventMask,                    "GetEventMask" },
+    { GetFirstClient,                  "GetFirstClient" },
+    { GetFirstRegion,                  "GetFirstRegion" },
+    { GetFirstTuple,                   "GetFirstTuple" },
+    { GetNextClient,                   "GetNextClient" },
+    { GetNextRegion,                   "GetNextRegion" },
+    { GetNextTuple,                    "GetNextTuple" },
+    { GetStatus,                       "GetStatus" },
+    { GetTupleData,                    "GetTupleData" },
+    { MapMemPage,                      "MapMemPage" },
+    { ModifyConfiguration,             "ModifyConfiguration" },
+    { ModifyWindow,                    "ModifyWindow" },
+    { OpenMemory,                      "OpenMemory" },
+    { ParseTuple,                      "ParseTuple" },
+    { ReadMemory,                      "ReadMemory" },
+    { RegisterClient,                  "RegisterClient" },
+    { RegisterEraseQueue,              "RegisterEraseQueue" },
+    { RegisterMTD,                     "RegisterMTD" },
+    { ReleaseConfiguration,            "ReleaseConfiguration" },
+    { ReleaseIO,                       "ReleaseIO" },
+    { ReleaseIRQ,                      "ReleaseIRQ" },
+    { ReleaseWindow,                   "ReleaseWindow" },
+    { RequestConfiguration,            "RequestConfiguration" },
+    { RequestIO,                       "RequestIO" },
+    { RequestIRQ,                      "RequestIRQ" },
+    { RequestSocketMask,               "RequestSocketMask" },
+    { RequestWindow,                   "RequestWindow" },
+    { ResetCard,                       "ResetCard" },
+    { SetEventMask,                    "SetEventMask" },
+    { ValidateCIS,                     "ValidateCIS" },
+    { WriteMemory,                     "WriteMemory" },
+    { BindDevice,                      "BindDevice" },
+    { BindMTD,                         "BindMTD" },
+    { ReportError,                     "ReportError" },
+    { SuspendCard,                     "SuspendCard" },
+    { ResumeCard,                      "ResumeCard" },
+    { EjectCard,                       "EjectCard" },
+    { InsertCard,                      "InsertCard" },
+    { ReplaceCIS,                      "ReplaceCIS" }
+};
+#define SERVICE_COUNT (sizeof(service_table)/sizeof(lookup_t))
+
+/*======================================================================
+
+    Reset a socket to the default state
+    
+======================================================================*/
+
+static void init_socket(socket_info_t *s)
+{
+    int i;
+    pccard_io_map io = { 0, 0, 0, 0, 1 };
+    pccard_mem_map mem = { 0, 0, 0, 0, 0, 0 };
+
+    mem.sys_stop = s->cap.map_size;
+    s->socket = dead_socket;
+    s->ss_entry(s->sock, SS_SetSocket, &s->socket);
+    for (i = 0; i < 2; i++) {
+       io.map = i;
+       s->ss_entry(s->sock, SS_SetIOMap, &io);
+    }
+    for (i = 0; i < 5; i++) {
+       mem.map = i;
+       s->ss_entry(s->sock, SS_SetMemMap, &mem);
+    }
+}
+
+/*====================================================================*/
+
+#if defined(CONFIG_PROC_FS) && defined(PCMCIA_DEBUG)
+int proc_read_clients(char *buf, char **start, off_t pos,
+                     int count, int *eof, void *data)
+{
+    socket_info_t *s = data;
+    client_handle_t c;
+    char *p = buf;
+
+    for (c = s->clients; c; c = c->next)
+       p += sprintf(p, "fn %x: '%s' [attr 0x%04x] [state 0x%04x]\n",
+                    c->Function, c->dev_info, c->Attributes, c->state);
+    return (p - buf);
+}
+#endif
+
+/*======================================================================
+
+    Low-level PC Card interface drivers need to register with Card
+    Services using these calls.
+    
+======================================================================*/
+
+static void setup_socket(u_long i);
+static void shutdown_socket(u_long i);
+static void reset_socket(u_long i);
+static void unreset_socket(u_long i);
+static void parse_events(void *info, u_int events);
+
+int register_ss_entry(int nsock, ss_entry_t ss_entry)
+{
+    int i, ns;
+    socket_info_t *s;
+
+    DEBUG(0, ("cs: register_ss_entry(%d, 0x%p)\n", nsock, ss_entry));
+
+    for (ns = 0; ns < nsock; ns++) {
+       s = kmalloc(sizeof(struct socket_info_t), GFP_KERNEL);
+       memset(s, 0, sizeof(socket_info_t));
+    
+       s->ss_entry = ss_entry;
+       s->sock = ns;
+       s->setup.data = sockets;
+       s->setup.function = &setup_socket;
+       s->shutdown.data = sockets;
+       s->shutdown.function = &shutdown_socket;
+       /* base address = 0, map = 0 */
+       s->cis_mem.flags = 0;
+       s->cis_mem.speed = cis_speed;
+       s->erase_busy.next = s->erase_busy.prev = &s->erase_busy;
+       
+       for (i = 0; i < sockets; i++)
+           if (socket_table[i] == NULL) break;
+       socket_table[i] = s;
+       if (i == sockets) sockets++;
+
+       init_socket(s);
+       ss_entry(ns, SS_InquireSocket, &s->cap);
+#ifdef CONFIG_PROC_FS
+       if (proc_pccard) {
+           char name[3];
+#ifdef PCMCIA_DEBUG
+           struct proc_dir_entry *ent;
+#endif
+           sprintf(name, "%02d", i);
+           s->proc = create_proc_entry(name, S_IFDIR, proc_pccard);
+#ifdef PCMCIA_DEBUG
+           ent = create_proc_entry("clients", 0, s->proc);
+           ent->read_proc = proc_read_clients;
+           ent->data = s;
+#endif
+           ss_entry(ns, SS_ProcSetup, s->proc);
+       }
+#endif
+    }
+    
+    return 0;
+} /* register_ss_entry */
+
+/*====================================================================*/
+
+void unregister_ss_entry(ss_entry_t ss_entry)
+{
+    int i, j;
+    socket_info_t *s = NULL;
+    client_t *client;
+
+    for (;;) {
+       for (i = 0; i < sockets; i++) {
+           s = socket_table[i];
+           if (s->ss_entry == ss_entry) break;
+       }
+       if (i == sockets) {
+           break;
+       } else {
+#ifdef CONFIG_PROC_FS
+           if (proc_pccard) {
+               char name[3];
+               sprintf(name, "%02d", i);
+#ifdef PCMCIA_DEBUG
+               remove_proc_entry("clients", s->proc);
+#endif
+               remove_proc_entry(name, proc_pccard);
+           }
+#endif
+           while (s->clients) {
+               client = s->clients;
+               s->clients = s->clients->next;
+               kfree(client);
+           }
+           init_socket(s);
+           release_cis_mem(s);
+#ifdef CONFIG_CARDBUS
+           cb_release_cis_mem(s);
+#endif
+           s->ss_entry = NULL;
+           kfree(s);
+           socket_table[i] = NULL;
+           for (j = i; j < sockets-1; j++)
+               socket_table[j] = socket_table[j+1];
+           sockets--;
+       }
+    }
+    
+} /* unregister_ss_entry */
+
+/*======================================================================
+
+    Shutdown_Socket() and setup_socket() are scheduled using add_timer
+    calls by the main event handler when card insertion and removal
+    events are received.  Shutdown_Socket() unconfigures a socket and
+    turns off socket power.  Setup_socket() turns on socket power
+    and resets the socket, in two stages.
+
+======================================================================*/
+
+static void free_regions(memory_handle_t *list)
+{
+    memory_handle_t tmp;
+    while (*list != NULL) {
+       tmp = *list;
+       *list = tmp->info.next;
+       tmp->region_magic = 0;
+       kfree(tmp);
+    }
+}
+
+static int send_event(socket_info_t *s, event_t event, int priority);
+
+static void shutdown_socket(u_long i)
+{
+    socket_info_t *s = socket_table[i];
+    client_t **c;
+    
+    DEBUG(1, ("cs: shutdown_socket(%ld)\n", i));
+
+    /* Blank out the socket state */
+    s->state &= SOCKET_PRESENT|SOCKET_SETUP_PENDING;
+    init_socket(s);
+    s->irq.AssignedIRQ = s->irq.Config = 0;
+    s->functions = 0;
+    s->lock_count = 0;
+    s->cis_used = 0;
+    if (s->fake_cis) {
+       kfree(s->fake_cis);
+       s->fake_cis = NULL;
+    }
+#ifdef CONFIG_CARDBUS
+    cb_release_cis_mem(s);
+#endif
+    if (s->config) {
+       kfree(s->config);
+       s->config = NULL;
+    }
+    for (c = &s->clients; *c; ) {
+       if ((*c)->state & CLIENT_UNBOUND) {
+           client_t *d = *c;
+           *c = (*c)->next;
+           kfree(d);
+       } else {
+           c = &((*c)->next);
+       }
+    }
+    free_regions(&s->a_region);
+    free_regions(&s->c_region);
+} /* shutdown_socket */
+
+static void setup_socket(u_long i)
+{
+    int val;
+    socket_info_t *s = socket_table[i];
+
+    s->ss_entry(s->sock, SS_GetStatus, &val);
+    if (val & SS_DETECT) {
+       DEBUG(1, ("cs: setup_socket(%ld): applying power\n", i));
+       s->state |= SOCKET_PRESENT;
+       s->socket.flags = 0;
+       if (val & SS_3VCARD)
+           s->socket.Vcc = s->socket.Vpp = 33;
+       else if (!(val & SS_XVCARD))
+           s->socket.Vcc = s->socket.Vpp = 50;
+       else {
+           printk(KERN_NOTICE "cs: socket %ld: unsupported "
+                  "voltage key\n", i);
+           s->socket.Vcc = 0;
+       }
+       if (val & SS_CARDBUS) {
+           s->state |= SOCKET_CARDBUS;
+#ifndef CONFIG_CARDBUS
+           printk(KERN_NOTICE "cs: unsupported card type detected!\n");
+#endif
+       }
+       s->ss_entry(s->sock, SS_SetSocket, &s->socket);
+       s->setup.function = &reset_socket;
+       s->setup.expires = jiffies + vcc_settle;
+       add_timer(&s->setup);
+    } else
+       DEBUG(0, ("cs: setup_socket(%ld): no card!\n", i));
+} /* setup_socket */
+
+/*======================================================================
+
+    Reset_socket() and unreset_socket() handle hard resets.  Resets
+    have several causes: card insertion, a call to reset_socket, or
+    recovery from a suspend/resume cycle.  Unreset_socket() sends
+    a CS event that matches the cause of the reset.
+    
+======================================================================*/
+
+static void reset_socket(u_long i)
+{
+    socket_info_t *s = socket_table[i];
+
+    DEBUG(1, ("cs: resetting socket %ld\n", i));
+    s->socket.flags |= SS_OUTPUT_ENA | SS_RESET;
+    s->ss_entry(s->sock, SS_SetSocket, &s->socket);
+    udelay((long)reset_time);
+    s->socket.flags &= ~SS_RESET;
+    s->ss_entry(s->sock, SS_SetSocket, &s->socket);
+    s->unreset_timeout = 0;
+    s->setup.expires = jiffies + unreset_delay;
+    s->setup.function = &unreset_socket;
+    add_timer(&s->setup);
+} /* reset_socket */
+
+#define EVENT_MASK \
+(SOCKET_SETUP_PENDING|SOCKET_SUSPEND|SOCKET_RESET_PENDING)
+
+static void unreset_socket(u_long i)
+{
+    socket_info_t *s = socket_table[i];
+    int val;
+
+    s->ss_entry(s->sock, SS_GetStatus, &val);
+    if (val & SS_READY) {
+       DEBUG(1, ("cs: reset done on socket %ld\n", i));
+       if (s->state & SOCKET_SUSPEND) {
+           s->state &= ~EVENT_MASK;
+           if (verify_cis_cache(s) != 0)
+               parse_events(s, SS_DETECT);
+           else
+               send_event(s, CS_EVENT_PM_RESUME, CS_EVENT_PRI_LOW);
+       } else if (s->state & SOCKET_SETUP_PENDING) {
+           send_event(s, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW);
+           s->state &= ~SOCKET_SETUP_PENDING;
+       } else {
+           send_event(s, CS_EVENT_CARD_RESET, CS_EVENT_PRI_LOW);
+           s->reset_handle->event_callback_args.info = NULL;
+           EVENT(s->reset_handle, CS_EVENT_RESET_COMPLETE,
+                 CS_EVENT_PRI_LOW);
+           s->state &= ~EVENT_MASK;
+       }
+    } else {
+       DEBUG(2, ("cs: socket %ld not ready yet\n", i));
+       if (s->unreset_timeout > unreset_limit) {
+           printk(KERN_NOTICE "cs: socket %ld timed out during"
+                  " reset\n", i);
+           s->state &= ~EVENT_MASK;
+       } else {
+           s->unreset_timeout++;
+           s->setup.expires = jiffies + unreset_check;
+           add_timer(&s->setup);
+       }
+    }
+} /* unreset_socket */
+
+/*======================================================================
+
+    The central event handler.  Send_event() sends an event to all
+    valid clients.  Parse_events() interprets the event bits from
+    a card status change report.  Do_shotdown() handles the high
+    priority stuff associated with a card removal.
+    
+======================================================================*/
+
+static int send_event(socket_info_t *s, event_t event, int priority)
+{
+    client_t *client = s->clients;
+    int ret;
+    DEBUG(1, ("cs: send_event(sock %d, event %d, pri %d)\n",
+             s->sock, event, priority));
+    ret = 0;
+    for (; client; client = client->next) { 
+       if (client->state & (CLIENT_UNBOUND|CLIENT_STALE))
+           continue;
+       if (client->EventMask & event) {
+           ret = EVENT(client, event, priority);
+           if (ret != 0)
+               return ret;
+       }
+    }
+    return ret;
+} /* send_event */
+
+static void do_shutdown(socket_info_t *s)
+{
+    client_t *client;
+    if (s->state & SOCKET_SHUTDOWN_PENDING)
+       return;
+    s->state |= SOCKET_SHUTDOWN_PENDING;
+    send_event(s, CS_EVENT_CARD_REMOVAL, CS_EVENT_PRI_HIGH);
+    for (client = s->clients; client; client = client->next)
+       if (!(client->Attributes & INFO_MASTER_CLIENT))
+           client->state |= CLIENT_STALE;
+    if (s->state & (SOCKET_SETUP_PENDING|SOCKET_RESET_PENDING)) {
+       DEBUG(0, ("cs: flushing pending setup\n"));
+       del_timer(&s->setup);
+       s->state &= ~EVENT_MASK;
+    }
+    s->shutdown.expires = jiffies + shutdown_delay;
+    add_timer(&s->shutdown);
+    s->state &= ~SOCKET_PRESENT;
+}
+
+static void parse_events(void *info, u_int events)
+{
+    socket_info_t *s = info;
+    if (events & SS_DETECT) {
+       int status;
+       u_long flags;
+       spin_lock_irqsave(&s->lock, flags);
+       s->ss_entry(s->sock, SS_GetStatus, &status);
+       if ((s->state & SOCKET_PRESENT) &&
+           (!(s->state & SOCKET_SUSPEND) ||
+            !(status & SS_DETECT)))
+           do_shutdown(s);
+       if (status & SS_DETECT) {
+           if (s->state & SOCKET_SETUP_PENDING) {
+               del_timer(&s->setup);
+               DEBUG(1, ("cs: delaying pending setup\n"));
+           }
+           s->state |= SOCKET_SETUP_PENDING;
+           s->setup.function = &setup_socket;
+           if (s->state & SOCKET_SUSPEND)
+               s->setup.expires = jiffies + resume_delay;
+           else
+               s->setup.expires = jiffies + setup_delay;
+           add_timer(&s->setup);
+       }
+       spin_unlock_irqrestore(&s->lock, flags);
+    }
+    if (events & SS_BATDEAD)
+       send_event(s, CS_EVENT_BATTERY_DEAD, CS_EVENT_PRI_LOW);
+    if (events & SS_BATWARN)
+       send_event(s, CS_EVENT_BATTERY_LOW, CS_EVENT_PRI_LOW);
+    if (events & SS_READY) {
+       if (!(s->state & SOCKET_RESET_PENDING))
+           send_event(s, CS_EVENT_READY_CHANGE, CS_EVENT_PRI_LOW);
+       else DEBUG(1, ("cs: ready change during reset\n"));
+    }
+} /* parse_events */
+
+/*======================================================================
+
+    Another event handler, for power management events.
+
+    This does not comply with the latest PC Card spec for handling
+    power management events.
+    
+======================================================================*/
+
+#ifdef CONFIG_APM
+static int handle_apm_event(apm_event_t event)
+{
+    int i, stat;
+    socket_info_t *s;
+    static int down = 0;
+    
+    switch (event) {
+    case APM_SYS_SUSPEND:
+    case APM_USER_SUSPEND:
+       DEBUG(1, ("cs: received suspend notification\n"));
+       if (down) {
+           printk(KERN_DEBUG "cs: received extra suspend event\n");
+           break;
+       }
+       down = 1;
+       for (i = 0; i < sockets; i++) {
+           s = socket_table[i];
+           if ((s->state & SOCKET_PRESENT) &&
+               !(s->state & SOCKET_SUSPEND)){
+               send_event(s, CS_EVENT_PM_SUSPEND, CS_EVENT_PRI_LOW);
+               s->ss_entry(s->sock, SS_SetSocket, &dead_socket);
+               s->state |= SOCKET_SUSPEND;
+           }
+       }
+       break;
+    case APM_NORMAL_RESUME:
+    case APM_CRITICAL_RESUME:
+       DEBUG(1, ("cs: received resume notification\n"));
+       if (!down) {
+           printk(KERN_DEBUG "cs: received bogus resume event\n");
+           break;
+       }
+       down = 0;
+       for (i = 0; i < sockets; i++) {
+           s = socket_table[i];
+           /* Do this just to reinitialize the socket */
+           init_socket(s);
+           s->ss_entry(s->sock, SS_GetStatus, &stat);
+           /* If there was or is a card here, we need to do something
+              about it... but parse_events will sort it all out. */
+                   if ((s->state & SOCKET_PRESENT) || (stat & SS_DETECT))
+               parse_events(s, SS_DETECT);
+       }
+       break;
+    }
+    return 0;
+} /* handle_apm_event */
+#endif
+
+/*======================================================================
+
+    Special stuff for managing IO windows, because they are scarce.
+    
+======================================================================*/
+
+static int alloc_io_space(socket_info_t *s, u_int attr, ioaddr_t *base,
+                         ioaddr_t num, char *name)
+{
+    int i;
+    ioaddr_t try;
+    
+    for (i = 0; i < MAX_IO_WIN; i++) {
+       if (s->io[i].NumPorts == 0) {
+           if (find_io_region(base, num, name) == 0) {
+               s->io[i].Attributes = attr;
+               s->io[i].BasePort = *base;
+               s->io[i].NumPorts = s->io[i].InUse = num;
+               break;
+           } else
+               return 1;
+       } else if (s->io[i].Attributes != attr)
+           continue;
+       /* Try to extend top of window */
+       try = s->io[i].BasePort + s->io[i].NumPorts;
+       if ((*base == 0) || (*base == try))
+           if (find_io_region(&try, num, name) == 0) {
+               *base = try;
+               s->io[i].NumPorts += num;
+               s->io[i].InUse += num;
+               break;
+           }
+       /* Try to extend bottom of window */
+       try = s->io[i].BasePort - num;
+       if ((*base == 0) || (*base == try))
+           if (find_io_region(&try, num, name) == 0) {
+               s->io[i].BasePort = *base = try;
+               s->io[i].NumPorts += num;
+               s->io[i].InUse += num;
+               break;
+           }
+    }
+    return (i == MAX_IO_WIN);
+} /* alloc_io_space */
+
+static void release_io_space(socket_info_t *s, ioaddr_t base,
+                            ioaddr_t num)
+{
+    int i;
+    release_region(base, num);
+    for (i = 0; i < MAX_IO_WIN; i++) {
+       if ((s->io[i].BasePort <= base) &&
+           (s->io[i].BasePort+s->io[i].NumPorts >= base+num)) {
+           s->io[i].InUse -= num;
+           /* Free the window if no one else is using it */
+           if (s->io[i].InUse == 0)
+               s->io[i].NumPorts = 0;
+       }
+    }
+}
+
+/*======================================================================
+
+    Access_configuration_register() reads and writes configuration
+    registers in attribute memory.  Memory window 0 is reserved for
+    this and the tuple reading services.
+    
+======================================================================*/
+
+static int access_configuration_register(client_handle_t handle,
+                                        conf_reg_t *reg)
+{
+    socket_info_t *s;
+    config_t *c;
+    int addr;
+    u_char val;
+    
+    if (CHECK_HANDLE(handle))
+       return CS_BAD_HANDLE;
+    s = SOCKET(handle);
+    if (handle->Function == BIND_FN_ALL) {
+       if (reg->Function >= s->functions)
+           return CS_BAD_ARGS;
+       c = &s->config[reg->Function];
+    } else
+       c = CONFIG(handle);
+    if (!(c->state & CONFIG_LOCKED))
+       return CS_CONFIGURATION_LOCKED;
+
+    addr = (c->ConfigBase + reg->Offset) >> 1;
+    
+    switch (reg->Action) {
+    case CS_READ:
+       read_cis_mem(s, 1, addr, 1, &val);
+       reg->Value = val;
+       break;
+    case CS_WRITE:
+       val = reg->Value;
+       write_cis_mem(s, 1, addr, 1, &val);
+       break;
+    default:
+       return CS_BAD_ARGS;
+       break;
+    }
+    return CS_SUCCESS;
+} /* access_configuration_register */
+
+/*======================================================================
+
+    Bind_device() associates a device driver with a particular socket.
+    It is normally called by Driver Services after it has identified
+    a newly inserted card.  An instance of that driver will then be
+    eligible to register as a client of this socket.
+    
+======================================================================*/
+
+static int bind_device(bind_req_t *req)
+{
+    client_t *client;
+    socket_info_t *s;
+
+    if (CHECK_SOCKET(req->Socket))
+       return CS_BAD_SOCKET;
+    s = SOCKET(req);
+
+    client = (client_t *)kmalloc(sizeof(client_t), GFP_KERNEL);
+    memset(client, '\0', sizeof(client_t));
+    client->client_magic = CLIENT_MAGIC;
+    strncpy(client->dev_info, (char *)req->dev_info, DEV_NAME_LEN);
+    client->Socket = req->Socket;
+    client->Function = req->Function;
+    client->state = CLIENT_UNBOUND;
+    client->erase_busy.next = &client->erase_busy;
+    client->erase_busy.prev = &client->erase_busy;
+    init_waitqueue_head(&client->mtd_req);
+    client->next = s->clients;
+    s->clients = client;
+    DEBUG(1, ("cs: bind_device(): client 0x%p, sock %d, dev %s\n",
+             client, client->Socket, client->dev_info));
+    return CS_SUCCESS;
+} /* bind_device */
+
+/*======================================================================
+
+    Bind_mtd() associates a device driver with a particular memory
+    region.  It is normally called by Driver Services after it has
+    identified a memory device type.  An instance of the corresponding
+    driver will then be able to register to control this region.
+    
+======================================================================*/
+
+static int bind_mtd(mtd_bind_t *req)
+{
+    socket_info_t *s;
+    memory_handle_t region;
+    
+    if (CHECK_SOCKET(req->Socket))
+       return CS_BAD_SOCKET;
+    s = SOCKET(req);
+    
+    if (req->Attributes & REGION_TYPE_AM)
+       region = s->a_region;
+    else
+       region = s->c_region;
+    
+    while (region) {
+       if (region->info.CardOffset == req->CardOffset) break;
+       region = region->info.next;
+    }
+    if (!region || (region->mtd != NULL))
+       return CS_BAD_OFFSET;
+    strncpy(region->dev_info, (char *)req->dev_info, DEV_NAME_LEN);
+    
+    DEBUG(1, ("cs: bind_mtd(): attr 0x%x, offset 0x%x, dev %s\n",
+         req->Attributes, req->CardOffset, (char *)req->dev_info));
+    return CS_SUCCESS;
+} /* bind_mtd */
+
+/*====================================================================*/
+
+static int deregister_client(client_handle_t handle)
+{
+    client_t **client;
+    socket_info_t *s;
+    memory_handle_t region;
+    u_long flags;
+    int i, sn;
+    
+    DEBUG(1, ("cs: deregister_client(%p)\n", handle));
+    if (CHECK_HANDLE(handle))
+       return CS_BAD_HANDLE;
+    if (handle->state &
+       (CLIENT_IRQ_REQ|CLIENT_IO_REQ|CLIENT_CONFIG_LOCKED))
+       return CS_IN_USE;
+    for (i = 0; i < MAX_WIN; i++)
+       if (handle->state & CLIENT_WIN_REQ(i))
+           return CS_IN_USE;
+
+    /* Disconnect all MTD links */
+    s = SOCKET(handle);
+    if (handle->mtd_count) {
+       for (region = s->a_region; region; region = region->info.next)
+           if (region->mtd == handle) region->mtd = NULL;
+       for (region = s->c_region; region; region = region->info.next)
+           if (region->mtd == handle) region->mtd = NULL;
+    }
+    
+    sn = handle->Socket; s = socket_table[sn];
+
+    if ((handle->state & CLIENT_STALE) ||
+       (handle->Attributes & INFO_MASTER_CLIENT)) {
+       spin_lock_irqsave(&s->lock, flags);
+       client = &s->clients;
+       while ((*client) && ((*client) != handle))
+           client = &(*client)->next;
+       if (*client == NULL)
+           return CS_BAD_HANDLE;
+       *client = handle->next;
+       handle->client_magic = 0;
+       kfree(handle);
+       spin_unlock_irqrestore(&s->lock, flags);
+    } else {
+       handle->state = CLIENT_UNBOUND;
+       handle->mtd_count = 0;
+       handle->event_handler = NULL;
+    }
+
+    if (--s->real_clients == 0)
+       s->ss_entry(sn, SS_RegisterCallback, NULL);
+    
+    return CS_SUCCESS;
+} /* deregister_client */
+
+/*====================================================================*/
+
+static int get_configuration_info(client_handle_t handle,
+                                 config_info_t *config)
+{
+    socket_info_t *s;
+    config_t *c;
+    
+    if (CHECK_HANDLE(handle))
+       return CS_BAD_HANDLE;
+    s = SOCKET(handle);
+    if (!(s->state & SOCKET_PRESENT))
+       return CS_NO_CARD;
+
+    if (handle->Function == BIND_FN_ALL) {
+       if (config->Function && (config->Function >= s->functions))
+           return CS_BAD_ARGS;
+    } else
+       config->Function = handle->Function;
+    
+#ifdef CONFIG_CARDBUS
+    if (s->state & SOCKET_CARDBUS) {
+       u_char fn = config->Function;
+       memset(config, 0, sizeof(config_info_t));
+       config->Function = fn;
+       config->Vcc = s->socket.Vcc;
+       config->Vpp1 = config->Vpp2 = s->socket.Vpp;
+       config->Option = s->cap.cardbus;
+       if (s->cb_config) {
+           config->Attributes = CONF_VALID_CLIENT;
+           config->IntType = INT_CARDBUS;
+           config->AssignedIRQ = s->irq.AssignedIRQ;
+           if (config->AssignedIRQ)
+               config->Attributes |= CONF_ENABLE_IRQ;
+           config->BasePort1 = s->io[0].BasePort;
+           config->NumPorts1 = s->io[0].NumPorts;
+       }
+       return CS_SUCCESS;
+    }
+#endif
+    
+    c = (s->config != NULL) ? &s->config[config->Function] : NULL;
+    
+    if ((c == NULL) || !(c->state & CONFIG_LOCKED)) {
+       config->Attributes = 0;
+       config->Vcc = s->socket.Vcc;
+       config->Vpp1 = config->Vpp2 = s->socket.Vpp;
+       return CS_SUCCESS;
+    }
+    
+    /* !!! This is a hack !!! */
+    memcpy(&config->Attributes, &c->Attributes, sizeof(config_t));
+    config->Attributes |= CONF_VALID_CLIENT;
+    config->CardValues = c->CardValues;
+    config->IRQAttributes = c->irq.Attributes;
+    config->AssignedIRQ = s->irq.AssignedIRQ;
+    config->BasePort1 = c->io.BasePort1;
+    config->NumPorts1 = c->io.NumPorts1;
+    config->Attributes1 = c->io.Attributes1;
+    config->BasePort2 = c->io.BasePort2;
+    config->NumPorts2 = c->io.NumPorts2;
+    config->Attributes2 = c->io.Attributes2;
+    config->IOAddrLines = c->io.IOAddrLines;
+    
+    return CS_SUCCESS;
+} /* get_configuration_info */
+
+/*======================================================================
+
+    Return information about this version of Card Services.
+    
+======================================================================*/
+
+static int get_card_services_info(servinfo_t *info)
+{
+    info->Signature[0] = 'C';
+    info->Signature[1] = 'S';
+    info->Count = sockets;
+    info->Revision = CS_RELEASE_CODE;
+    info->CSLevel = 0x0210;
+    info->VendorString = (char *)release;
+    return CS_SUCCESS;
+} /* get_card_services_info */
+
+/*======================================================================
+
+    Note that get_first_client() *does* recognize the Socket field
+    in the request structure.
+    
+======================================================================*/
+
+static int get_first_client(client_handle_t *handle, client_req_t *req)
+{
+    socket_t s;
+    if (req->Attributes & CLIENT_THIS_SOCKET)
+       s = req->Socket;
+    else
+       s = 0;
+    if (CHECK_SOCKET(req->Socket))
+       return CS_BAD_SOCKET;
+    if (socket_table[s]->clients == NULL)
+       return CS_NO_MORE_ITEMS;
+    *handle = socket_table[s]->clients;
+    return CS_SUCCESS;
+} /* get_first_client */
+
+/*====================================================================*/
+
+static int get_next_client(client_handle_t *handle, client_req_t *req)
+{
+    socket_info_t *s;
+    if ((handle == NULL) || CHECK_HANDLE(*handle))
+       return CS_BAD_HANDLE;
+    if ((*handle)->next == NULL) {
+       if (req->Attributes & CLIENT_THIS_SOCKET)
+           return CS_NO_MORE_ITEMS;
+       s = SOCKET(*handle);
+       if (s->clients == NULL)
+           return CS_NO_MORE_ITEMS;
+       *handle = s->clients;
+    } else
+       *handle = (*handle)->next;
+    return CS_SUCCESS;
+} /* get_next_client */
+
+/*======================================================================
+
+    Get the current socket state bits.  We don't support the latched
+    SocketState yet: I haven't seen any point for it.
+    
+======================================================================*/
+
+static int get_status(client_handle_t handle, cs_status_t *status)
+{
+    socket_info_t *s;
+    config_t *c;
+    int val;
+    
+    if (CHECK_HANDLE(handle))
+       return CS_BAD_HANDLE;
+    s = SOCKET(handle);
+    s->ss_entry(s->sock, SS_GetStatus, &val);
+    status->CardState = status->SocketState = 0;
+    status->CardState |= (val & SS_DETECT) ? CS_EVENT_CARD_DETECT : 0;
+    status->CardState |= (val & SS_CARDBUS) ? CS_EVENT_CB_DETECT : 0;
+    status->CardState |= (val & SS_3VCARD) ? CS_EVENT_3VCARD : 0;
+    status->CardState |= (val & SS_XVCARD) ? CS_EVENT_XVCARD : 0;
+    if (s->state & SOCKET_SUSPEND)
+       status->CardState |= CS_EVENT_PM_SUSPEND;
+    if (!(s->state & SOCKET_PRESENT))
+       return CS_NO_CARD;
+    if (s->state & SOCKET_SETUP_PENDING)
+       status->CardState |= CS_EVENT_CARD_INSERTION;
+    
+    /* Get info from the PRR, if necessary */
+    if (handle->Function == BIND_FN_ALL) {
+       if (status->Function && (status->Function >= s->functions))
+           return CS_BAD_ARGS;
+       c = (s->config != NULL) ? &s->config[status->Function] : NULL;
+    } else
+       c = CONFIG(handle);
+    if ((c != NULL) && (c->state & CONFIG_LOCKED) &&
+       (c->IntType & INT_MEMORY_AND_IO)) {
+       u_char reg;
+       if (c->Present & PRESENT_PIN_REPLACE) {
+           read_cis_mem(s, 1, (c->ConfigBase+CISREG_PRR)>>1, 1, &reg);
+           status->CardState |=
+               (reg & PRR_WP_STATUS) ? CS_EVENT_WRITE_PROTECT : 0;
+           status->CardState |=
+               (reg & PRR_READY_STATUS) ? CS_EVENT_READY_CHANGE : 0;
+           status->CardState |=
+               (reg & PRR_BVD2_STATUS) ? CS_EVENT_BATTERY_LOW : 0;
+           status->CardState |=
+               (reg & PRR_BVD1_STATUS) ? CS_EVENT_BATTERY_DEAD : 0;
+       } else {
+           /* No PRR?  Then assume we're always ready */
+           status->CardState |= CS_EVENT_READY_CHANGE;
+       }
+       if (c->Present & PRESENT_EXT_STATUS) {
+           read_cis_mem(s, 1, (c->ConfigBase+CISREG_ESR)>>1, 1, &reg);
+           status->CardState |=
+               (reg & ESR_REQ_ATTN) ? CS_EVENT_REQUEST_ATTENTION : 0;
+       }
+       return CS_SUCCESS;
+    }
+    status->CardState |=
+       (val & SS_WRPROT) ? CS_EVENT_WRITE_PROTECT : 0;
+    status->CardState |=
+       (val & SS_BATDEAD) ? CS_EVENT_BATTERY_DEAD : 0;
+    status->CardState |=
+       (val & SS_BATWARN) ? CS_EVENT_BATTERY_LOW : 0;
+    status->CardState |=
+       (val & SS_READY) ? CS_EVENT_READY_CHANGE : 0;
+    return CS_SUCCESS;
+} /* get_status */
+
+/*======================================================================
+
+    Change the card address of an already open memory window.
+    
+======================================================================*/
+
+static int map_mem_page(window_handle_t win, memreq_t *req)
+{
+    socket_info_t *s;
+    if ((win == NULL) || (win->magic != WINDOW_MAGIC))
+       return CS_BAD_HANDLE;
+    if (req->Page != 0)
+       return CS_BAD_PAGE;
+
+    s = win->sock;
+    win->ctl.card_start = req->CardOffset;
+    if (s->ss_entry(s->sock, SS_SetMemMap, &win->ctl) != 0)
+       return CS_BAD_OFFSET;
+    return CS_SUCCESS;
+} /* map_mem_page */
+
+/*======================================================================
+
+    Modify a locked socket configuration
+    
+======================================================================*/
+
+static int modify_configuration(client_handle_t handle,
+                               modconf_t *mod)
+{
+    socket_info_t *s;
+    config_t *c;
+    
+    if (CHECK_HANDLE(handle))
+       return CS_BAD_HANDLE;
+    s = SOCKET(handle); c = CONFIG(handle);
+    if (!(s->state & SOCKET_PRESENT))
+       return CS_NO_CARD;
+    if (!(c->state & CONFIG_LOCKED))
+       return CS_CONFIGURATION_LOCKED;
+    
+    if (mod->Attributes & CONF_IRQ_CHANGE_VALID) {
+       if (mod->Attributes & CONF_ENABLE_IRQ) {
+           c->Attributes |= CONF_ENABLE_IRQ;
+           s->socket.io_irq = s->irq.AssignedIRQ;
+       } else {
+           c->Attributes &= ~CONF_ENABLE_IRQ;
+           s->socket.io_irq = 0;
+       }
+       s->ss_entry(s->sock, SS_SetSocket, &s->socket);
+    }
+
+    if (mod->Attributes & CONF_VCC_CHANGE_VALID)
+       return CS_BAD_VCC;
+
+    /* We only allow changing Vpp1 and Vpp2 to the same value */
+    if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) &&
+       (mod->Attributes & CONF_VPP2_CHANGE_VALID)) {
+       if (mod->Vpp1 != mod->Vpp2)
+           return CS_BAD_VPP;
+       c->Vpp1 = c->Vpp2 = s->socket.Vpp = mod->Vpp1;
+       if (s->ss_entry(s->sock, SS_SetSocket, &s->socket))
+           return CS_BAD_VPP;
+    } else if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) ||
+              (mod->Attributes & CONF_VPP2_CHANGE_VALID))
+       return CS_BAD_VPP;
+
+    return CS_SUCCESS;
+} /* modify_configuration */
+
+/*======================================================================
+
+    Modify the attributes of a window returned by RequestWindow.
+
+======================================================================*/
+
+static int modify_window(window_handle_t win, modwin_t *req)
+{
+    if ((win == NULL) || (win->magic != WINDOW_MAGIC))
+       return CS_BAD_HANDLE;
+
+    win->ctl.flags &= ~(MAP_ATTRIB|MAP_ACTIVE);
+    if (req->Attributes & WIN_MEMORY_TYPE)
+       win->ctl.flags |= MAP_ATTRIB;
+    if (req->Attributes & WIN_ENABLE)
+       win->ctl.flags |= MAP_ACTIVE;
+    if (req->Attributes & WIN_DATA_WIDTH)
+       win->ctl.flags |= MAP_16BIT;
+    if (req->Attributes & WIN_USE_WAIT)
+       win->ctl.flags |= MAP_USE_WAIT;
+    win->ctl.speed = req->AccessSpeed;
+    win->sock->ss_entry(win->sock->sock, SS_SetMemMap, &win->ctl);
+    
+    return CS_SUCCESS;
+} /* modify_window */
+
+/*======================================================================
+
+    Register_client() uses the dev_info_t handle to match the
+    caller with a socket.  The driver must have already been bound
+    to a socket with bind_device() -- in fact, bind_device()
+    allocates the client structure that will be used.
+    
+======================================================================*/
+
+static int register_client(client_handle_t *handle, client_reg_t *req)
+{
+    client_t *client;
+    socket_info_t *s;
+    socket_t ns;
+    
+    /* Look for unbound client with matching dev_info */
+    client = NULL;
+    for (ns = 0; ns < sockets; ns++) {
+       client = socket_table[ns]->clients;
+       while (client != NULL) {
+           if ((strcmp(client->dev_info, (char *)req->dev_info) == 0)
+               && (client->state & CLIENT_UNBOUND)) break;
+           client = client->next;
+       }
+       if (client != NULL) break;
+    }
+    if (client == NULL)
+       return CS_OUT_OF_RESOURCE;
+
+    s = socket_table[ns];
+    if (++s->real_clients == 1) {
+       ss_callback_t call;
+       int status;
+       call.handler = &parse_events;
+       call.info = s;
+       s->ss_entry(ns, SS_RegisterCallback, &call);
+       s->ss_entry(ns, SS_GetStatus, &status);
+       if ((status & SS_DETECT) &&
+           !(s->state & SOCKET_SETUP_PENDING)) {
+           s->state |= SOCKET_SETUP_PENDING;
+           setup_socket(ns);
+       }
+    }
+
+    *handle = client;
+    client->state &= ~CLIENT_UNBOUND;
+    client->Socket = ns;
+    client->Attributes = req->Attributes;
+    client->EventMask = req->EventMask;
+    client->event_handler = req->event_handler;
+    client->event_callback_args = req->event_callback_args;
+    client->event_callback_args.client_handle = client;
+    client->event_callback_args.bus = s->cap.bus;
+
+    if (s->state & SOCKET_CARDBUS)
+       client->state |= CLIENT_CARDBUS;
+    
+    if ((!(s->state & SOCKET_CARDBUS)) && (s->functions == 0) &&
+       (client->Function != BIND_FN_ALL)) {
+       cistpl_longlink_mfc_t mfc;
+       if (read_tuple(client, CISTPL_LONGLINK_MFC, &mfc)
+           == CS_SUCCESS)
+           s->functions = mfc.nfn;
+       else
+           s->functions = 1;
+       s->config = kmalloc(sizeof(config_t) * s->functions,
+                           GFP_KERNEL);
+       memset(s->config, 0, sizeof(config_t) * s->functions);
+    }
+    
+    DEBUG(1, ("cs: register_client(): client 0x%p, sock %d, dev %s\n",
+             client, client->Socket, client->dev_info));
+    if (client->EventMask & CS_EVENT_REGISTRATION_COMPLETE)
+       EVENT(client, CS_EVENT_REGISTRATION_COMPLETE, CS_EVENT_PRI_LOW);
+    if ((socket_table[ns]->state & SOCKET_PRESENT) &&
+       !(socket_table[ns]->state & SOCKET_SETUP_PENDING)) {
+       if (client->EventMask & CS_EVENT_CARD_INSERTION)
+           EVENT(client, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW);
+       else
+           client->PendingEvents |= CS_EVENT_CARD_INSERTION;
+    }
+    return CS_SUCCESS;
+} /* register_client */
+
+/*====================================================================*/
+
+static int release_configuration(client_handle_t handle,
+                                socket_t *Socket)
+{
+    pccard_io_map io;
+    socket_info_t *s;
+    int i;
+    
+    if (CHECK_HANDLE(handle) ||
+       !(handle->state & CLIENT_CONFIG_LOCKED))
+       return CS_BAD_HANDLE;
+    handle->state &= ~CLIENT_CONFIG_LOCKED;
+    s = SOCKET(handle);
+    
+#ifdef CONFIG_CARDBUS
+    if (handle->state & CLIENT_CARDBUS) {
+       cb_disable(s);
+       s->lock_count = 0;
+       return CS_SUCCESS;
+    }
+#endif
+    
+    if (!(handle->state & CLIENT_STALE)) {
+       config_t *c = CONFIG(handle);
+       if (--(s->lock_count) == 0) {
+           s->socket.flags = SS_OUTPUT_ENA;
+           s->socket.Vpp = 0;
+           s->socket.io_irq = 0;
+           s->ss_entry(s->sock, SS_SetSocket, &s->socket);
+       }
+       if (c->state & CONFIG_IO_REQ)
+           for (i = 0; i < MAX_IO_WIN; i++) {
+               if (s->io[i].NumPorts == 0)
+                   continue;
+               s->io[i].Config--;
+               if (s->io[i].Config != 0)
+                   continue;
+               io.map = i;
+               s->ss_entry(s->sock, SS_GetIOMap, &io);
+               io.flags &= ~MAP_ACTIVE;
+               s->ss_entry(s->sock, SS_SetIOMap, &io);
+           }
+       c->state &= ~CONFIG_LOCKED;
+    }
+    
+    return CS_SUCCESS;
+} /* release_configuration */
+
+/*======================================================================
+
+    Release_io() releases the I/O ranges allocated by a client.  This
+    may be invoked some time after a card ejection has already dumped
+    the actual socket configuration, so if the client is "stale", we
+    don't bother checking the port ranges against the current socket
+    values.
+    
+======================================================================*/
+
+static int release_io(client_handle_t handle, io_req_t *req)
+{
+    socket_info_t *s;
+    
+    if (CHECK_HANDLE(handle) || !(handle->state & CLIENT_IO_REQ))
+       return CS_BAD_HANDLE;
+    handle->state &= ~CLIENT_IO_REQ;
+    s = SOCKET(handle);
+    
+#ifdef CONFIG_CARDBUS
+    if (handle->state & CLIENT_CARDBUS) {
+       cb_release(s);
+       return CS_SUCCESS;
+    }
+#endif
+    
+    if (!(handle->state & CLIENT_STALE)) {
+       config_t *c = CONFIG(handle);
+       if (c->state & CONFIG_LOCKED)
+           return CS_CONFIGURATION_LOCKED;
+       if ((c->io.BasePort1 != req->BasePort1) ||
+           (c->io.NumPorts1 != req->NumPorts1) ||
+           (c->io.BasePort2 != req->BasePort2) ||
+           (c->io.NumPorts2 != req->NumPorts2))
+           return CS_BAD_ARGS;
+       c->state &= ~CONFIG_IO_REQ;
+    }
+
+    release_io_space(s, req->BasePort1, req->NumPorts1);
+    if (req->NumPorts2)
+       release_io_space(s, req->BasePort2, req->NumPorts2);
+    
+    return CS_SUCCESS;
+} /* release_io */
+
+/*====================================================================*/
+
+static int cs_release_irq(client_handle_t handle, irq_req_t *req)
+{
+    socket_info_t *s;
+    if (CHECK_HANDLE(handle) || !(handle->state & CLIENT_IRQ_REQ))
+       return CS_BAD_HANDLE;
+    handle->state &= ~CLIENT_IRQ_REQ;
+    s = SOCKET(handle);
+    
+    if (!(handle->state & CLIENT_STALE)) {
+       config_t *c = CONFIG(handle);
+       if (c->state & CONFIG_LOCKED)
+           return CS_CONFIGURATION_LOCKED;
+       if (c->irq.Attributes != req->Attributes)
+           return CS_BAD_ATTRIBUTE;
+       if (s->irq.AssignedIRQ != req->AssignedIRQ)
+           return CS_BAD_IRQ;
+       if (--s->irq.Config == 0) {
+           c->state &= ~CONFIG_IRQ_REQ;
+           s->irq.AssignedIRQ = 0;
+       }
+    }
+    
+    if (req->Attributes & IRQ_HANDLE_PRESENT) {
+       bus_free_irq(s->cap.bus, req->AssignedIRQ, req->Instance);
+    }
+
+#ifdef CONFIG_ISA
+    if (req->AssignedIRQ != s->cap.pci_irq)
+       undo_irq(req->Attributes, req->AssignedIRQ);
+#endif
+    
+    return CS_SUCCESS;
+} /* cs_release_irq */
+
+/*====================================================================*/
+
+static int release_window(window_handle_t win)
+{
+    socket_info_t *s;
+    
+    if ((win == NULL) || (win->magic != WINDOW_MAGIC))
+       return CS_BAD_HANDLE;
+    s = win->sock;
+    if (!(win->handle->state & CLIENT_WIN_REQ(win->index)))
+       return CS_BAD_HANDLE;
+
+    /* Shut down memory window */
+    win->ctl.flags &= ~MAP_ACTIVE;
+    s->ss_entry(s->sock, SS_SetMemMap, &win->ctl);
+    s->state &= ~SOCKET_WIN_REQ(win->index);
+
+    /* Release system memory */
+    release_mem_region(win->base, win->size);
+    win->handle->state &= ~CLIENT_WIN_REQ(win->index);
+
+    win->magic = 0;
+    
+    return CS_SUCCESS;
+} /* release_window */
+
+/*====================================================================*/
+
+static int request_configuration(client_handle_t handle,
+                                config_req_t *req)
+{
+    int i;
+    u_int base;
+    socket_info_t *s;
+    config_t *c;
+    pccard_io_map iomap;
+    
+    if (CHECK_HANDLE(handle))
+       return CS_BAD_HANDLE;
+    i = handle->Socket; s = socket_table[i];
+    if (!(s->state & SOCKET_PRESENT))
+       return CS_NO_CARD;
+    
+#ifdef CONFIG_CARDBUS
+    if (handle->state & CLIENT_CARDBUS) {
+       if (!(req->IntType & INT_CARDBUS))
+           return CS_UNSUPPORTED_MODE;
+       if (s->lock_count != 0)
+           return CS_CONFIGURATION_LOCKED;
+       cb_enable(s);
+       handle->state |= CLIENT_CONFIG_LOCKED;
+       s->lock_count++;
+       return CS_SUCCESS;
+    }
+#endif
+    
+    if (req->IntType & INT_CARDBUS)
+       return CS_UNSUPPORTED_MODE;
+    c = CONFIG(handle);
+    if (c->state & CONFIG_LOCKED)
+       return CS_CONFIGURATION_LOCKED;
+
+    /* Do power control.  We don't allow changes in Vcc. */
+    if (s->socket.Vcc != req->Vcc)
+       return CS_BAD_VCC;
+    if (req->Vpp1 != req->Vpp2)
+       return CS_BAD_VPP;
+    s->socket.Vpp = req->Vpp1;
+    if (s->ss_entry(s->sock, SS_SetSocket, &s->socket))
+       return CS_BAD_VPP;
+    
+    c->Vcc = req->Vcc; c->Vpp1 = c->Vpp2 = req->Vpp1;
+    
+    /* Pick memory or I/O card, DMA mode, interrupt */
+    c->IntType = req->IntType;
+    c->Attributes = req->Attributes;
+    if (req->IntType & INT_MEMORY_AND_IO)
+       s->socket.flags |= SS_IOCARD;
+    if (req->Attributes & CONF_ENABLE_DMA)
+       s->socket.flags |= SS_DMA_MODE;
+    if (req->Attributes & CONF_ENABLE_SPKR)
+       s->socket.flags |= SS_SPKR_ENA;
+    if (req->Attributes & CONF_ENABLE_IRQ)
+       s->socket.io_irq = s->irq.AssignedIRQ;
+    else
+       s->socket.io_irq = 0;
+    s->ss_entry(s->sock, SS_SetSocket, &s->socket);
+    s->lock_count++;
+    
+    /* Set up CIS configuration registers */
+    base = c->ConfigBase = req->ConfigBase;
+    c->Present = c->CardValues = req->Present;
+    if (req->Present & PRESENT_COPY) {
+       c->Copy = req->Copy;
+       write_cis_mem(s, 1, (base + CISREG_SCR)>>1, 1, &c->Copy);
+    }
+    if (req->Present & PRESENT_OPTION) {
+       if (s->functions == 1)
+           c->Option = req->ConfigIndex & COR_CONFIG_MASK;
+       else {
+           c->Option = req->ConfigIndex & COR_MFC_CONFIG_MASK;
+           c->Option |= COR_FUNC_ENA|COR_ADDR_DECODE|COR_IREQ_ENA;
+       }
+       if (c->state & CONFIG_IRQ_REQ)
+           if (!(c->irq.Attributes & IRQ_FORCED_PULSE))
+               c->Option |= COR_LEVEL_REQ;
+       write_cis_mem(s, 1, (base + CISREG_COR)>>1, 1, &c->Option);
+       udelay(40*1000);
+    }
+    if (req->Present & PRESENT_STATUS) {
+       c->Status = req->Status;
+       write_cis_mem(s, 1, (base + CISREG_CCSR)>>1, 1, &c->Status);
+    }
+    if (req->Present & PRESENT_PIN_REPLACE) {
+       c->Pin = req->Pin;
+       write_cis_mem(s, 1, (base + CISREG_PRR)>>1, 1, &c->Pin);
+    }
+    if (req->Present & PRESENT_EXT_STATUS) {
+       c->ExtStatus = req->ExtStatus;
+       write_cis_mem(s, 1, (base + CISREG_ESR)>>1, 1, &c->ExtStatus);
+    }
+    if (req->Present & PRESENT_IOBASE_0) {
+       i = c->io.BasePort1 & 0xff;
+       write_cis_mem(s, 1, (base + CISREG_IOBASE_0)>>1, 1, &i);
+       i = (c->io.BasePort1 >> 8) & 0xff;
+       write_cis_mem(s, 1, (base + CISREG_IOBASE_1)>>1, 1, &i);
+    }
+    if (req->Present & PRESENT_IOSIZE) {
+       i = c->io.NumPorts1 + c->io.NumPorts2 - 1;
+       write_cis_mem(s, 1, (base + CISREG_IOSIZE)>>1, 1, &i);
+    }
+    
+    /* Configure I/O windows */
+    if (c->state & CONFIG_IO_REQ) {
+       iomap.speed = io_speed;
+       for (i = 0; i < MAX_IO_WIN; i++)
+           if (s->io[i].NumPorts != 0) {
+               iomap.map = i;
+               iomap.flags = MAP_ACTIVE;
+               switch (s->io[i].Attributes & IO_DATA_PATH_WIDTH) {
+               case IO_DATA_PATH_WIDTH_16:
+                   iomap.flags |= MAP_16BIT; break;
+               case IO_DATA_PATH_WIDTH_AUTO:
+                   iomap.flags |= MAP_AUTOSZ; break;
+               default:
+                   break;
+               }
+               iomap.start = s->io[i].BasePort;
+               iomap.stop = iomap.start + s->io[i].NumPorts - 1;
+               s->ss_entry(s->sock, SS_SetIOMap, &iomap);
+               s->io[i].Config++;
+           }
+    }
+    
+    c->state |= CONFIG_LOCKED;
+    handle->state |= CLIENT_CONFIG_LOCKED;
+    return CS_SUCCESS;
+} /* request_configuration */
+
+/*======================================================================
+  
+    Request_io() reserves ranges of port addresses for a socket.
+    I have not implemented range sharing or alias addressing.
+    
+======================================================================*/
+
+static int request_io(client_handle_t handle, io_req_t *req)
+{
+    socket_info_t *s;
+    config_t *c;
+    
+    if (CHECK_HANDLE(handle))
+       return CS_BAD_HANDLE;
+    s = SOCKET(handle);
+    if (!(s->state & SOCKET_PRESENT))
+       return CS_NO_CARD;
+
+    if (handle->state & CLIENT_CARDBUS) {
+#ifdef CONFIG_CARDBUS
+       int ret = cb_config(s);
+       if (ret == CS_SUCCESS)
+           handle->state |= CLIENT_IO_REQ;
+       return ret;
+#else
+       return CS_UNSUPPORTED_FUNCTION;
+#endif
+    }
+
+    if (!req)
+       return CS_UNSUPPORTED_MODE;
+    c = CONFIG(handle);
+    if (c->state & CONFIG_LOCKED)
+       return CS_CONFIGURATION_LOCKED;
+    if (c->state & CONFIG_IO_REQ)
+       return CS_IN_USE;
+    if (req->Attributes1 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS))
+       return CS_BAD_ATTRIBUTE;
+    if ((req->NumPorts2 > 0) &&
+       (req->Attributes2 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS)))
+       return CS_BAD_ATTRIBUTE;
+
+    if (alloc_io_space(s, req->Attributes1, &req->BasePort1,
+                      req->NumPorts1, handle->dev_info))
+       return CS_IN_USE;
+
+    if (req->NumPorts2) {
+       if (alloc_io_space(s, req->Attributes2, &req->BasePort2,
+                          req->NumPorts2, handle->dev_info)) {
+           release_io_space(s, req->BasePort1, req->NumPorts1);
+           return CS_IN_USE;
+       }
+    }
+
+    c->io = *req;
+    c->state |= CONFIG_IO_REQ;
+    handle->state |= CLIENT_IO_REQ;
+    return CS_SUCCESS;
+} /* request_io */
+
+/*======================================================================
+
+    Request_irq() reserves an irq for this client.
+
+    Also, since Linux only reserves irq's when they are actually
+    hooked, we don't guarantee that an irq will still be available
+    when the configuration is locked.  Now that I think about it,
+    there might be a way to fix this using a dummy handler.
+    
+======================================================================*/
+
+static int cs_request_irq(client_handle_t handle, irq_req_t *req)
+{
+    socket_info_t *s;
+    config_t *c;
+    int try, ret = 0, irq = 0;
+    u_int mask;
+    
+    if (CHECK_HANDLE(handle))
+       return CS_BAD_HANDLE;
+    s = SOCKET(handle);
+    if (!(s->state & SOCKET_PRESENT))
+       return CS_NO_CARD;
+    c = CONFIG(handle);
+    if (c->state & CONFIG_LOCKED)
+       return CS_CONFIGURATION_LOCKED;
+    if (c->state & CONFIG_IRQ_REQ)
+       return CS_IN_USE;
+    
+    /* Short cut: if the interrupt is PCI, there are no options */
+    if (s->cap.irq_mask == (1 << s->cap.pci_irq))
+       irq = s->cap.pci_irq;
+#ifdef CONFIG_ISA
+    else if (s->irq.AssignedIRQ != 0) {
+       /* If the interrupt is already assigned, it must match */
+       irq = s->irq.AssignedIRQ;
+       if (req->IRQInfo1 & IRQ_INFO2_VALID) {
+           mask = req->IRQInfo2 & s->cap.irq_mask;
+           ret = ((mask >> irq) & 1) ? 0 : CS_BAD_ARGS;
+       } else
+           ret = ((req->IRQInfo1&IRQ_MASK) == irq) ? 0 : CS_BAD_ARGS;
+    } else {
+       ret = CS_IN_USE;
+       if (req->IRQInfo1 & IRQ_INFO2_VALID) {
+           mask = req->IRQInfo2 & s->cap.irq_mask;
+           mask &= ~(1 << s->cap.pci_irq);
+           for (try = 0; try < 2; try++) {
+               for (irq = 0; irq < 32; irq++)
+                   if ((mask >> irq) & 1) {
+                       ret = try_irq(req->Attributes, irq, try);
+                       if (ret == 0) break;
+                   }
+               if (ret == 0) break;
+           }
+       } else {
+           irq = req->IRQInfo1 & IRQ_MASK;
+           ret = try_irq(req->Attributes, irq, 1);
+       }
+    }
+#endif
+    if (ret != 0) return ret;
+
+    if (req->Attributes & IRQ_HANDLE_PRESENT) {
+       if (bus_request_irq(s->cap.bus, irq, req->Handler,
+                           ((req->Attributes & IRQ_TYPE_DYNAMIC_SHARING) || 
+                            (s->functions > 1) ||
+                            (irq == s->cap.pci_irq)) ? SA_SHIRQ : 0,
+                           handle->dev_info, req->Instance))
+           return CS_IN_USE;
+    }
+
+    c->irq.Attributes = req->Attributes;
+    s->irq.AssignedIRQ = req->AssignedIRQ = irq;
+    s->irq.Config++;
+    
+    c->state |= CONFIG_IRQ_REQ;
+    handle->state |= CLIENT_IRQ_REQ;
+    return CS_SUCCESS;
+} /* cs_request_irq */
+
+/*======================================================================
+
+    Request_window() establishes a mapping between card memory space
+    and system memory space.
+
+======================================================================*/
+
+static int request_window(client_handle_t *handle, win_req_t *req)
+{
+    socket_info_t *s;
+    window_t *win;
+    int w;
+    
+    if (CHECK_HANDLE(*handle))
+       return CS_BAD_HANDLE;
+    s = SOCKET(*handle);
+    if (!(s->state & SOCKET_PRESENT))
+       return CS_NO_CARD;
+    if (req->Attributes & (WIN_PAGED | WIN_SHARED))
+       return CS_BAD_ATTRIBUTE;
+
+    for (w = 0; w < MAX_WIN; w++)
+       if (!(s->state & SOCKET_WIN_REQ(w))) break;
+    if (w == MAX_WIN)
+       return CS_OUT_OF_RESOURCE;
+
+    /* Window size defaults to smallest available */
+    if (req->Size == 0)
+       req->Size = s->cap.map_size;
+    
+    /* Allocate system memory window */
+    win = &s->win[w];
+    win->magic = WINDOW_MAGIC;
+    win->index = w;
+    win->handle = *handle;
+    win->sock = s;
+    win->base = req->Base;
+    win->size = req->Size;
+    if (find_mem_region(&win->base, win->size, (*handle)->dev_info,
+                       ((s->cap.features & SS_CAP_MEM_ALIGN) ?
+                        req->Size : s->cap.map_size),
+                       (req->Attributes & WIN_MAP_BELOW_1MB) ||
+                       !(s->cap.features & SS_CAP_PAGE_REGS)))
+       return CS_IN_USE;
+    req->Base = win->base;
+    (*handle)->state |= CLIENT_WIN_REQ(w);
+
+    /* Configure the socket controller */
+    win->ctl.map = w+1;
+    win->ctl.flags = 0;
+    win->ctl.speed = req->AccessSpeed;
+    if (req->Attributes & WIN_MEMORY_TYPE)
+       win->ctl.flags |= MAP_ATTRIB;
+    if (req->Attributes & WIN_ENABLE)
+       win->ctl.flags |= MAP_ACTIVE;
+    if (req->Attributes & WIN_DATA_WIDTH)
+       win->ctl.flags |= MAP_16BIT;
+    if (req->Attributes & WIN_USE_WAIT)
+       win->ctl.flags |= MAP_USE_WAIT;
+    win->ctl.sys_start = req->Base;
+    win->ctl.sys_stop = req->Base + req->Size-1;
+    win->ctl.card_start = 0;
+    if (s->ss_entry(s->sock, SS_SetMemMap, &win->ctl) != 0)
+       return CS_BAD_ARGS;
+    s->state |= SOCKET_WIN_REQ(w);
+
+    /* Return window handle */
+    *handle = (client_handle_t)win;
+    
+    return CS_SUCCESS;
+} /* request_window */
+
+/*======================================================================
+
+    I'm not sure which "reset" function this is supposed to use,
+    but for now, it uses the low-level interface's reset, not the
+    CIS register.
+    
+======================================================================*/
+
+static int reset_card(client_handle_t handle, client_req_t *req)
+{
+    int i, ret;
+    socket_info_t *s;
+    
+    if (CHECK_HANDLE(handle))
+       return CS_BAD_HANDLE;
+    i = handle->Socket; s = socket_table[i];
+    if (!(s->state & SOCKET_PRESENT))
+       return CS_NO_CARD;
+    if (s->state & SOCKET_RESET_PENDING)
+       return CS_IN_USE;
+    s->state |= SOCKET_RESET_PENDING;
+
+    ret = send_event(s, CS_EVENT_RESET_REQUEST, CS_EVENT_PRI_LOW);
+    if (ret != 0) {
+       s->state &= ~SOCKET_RESET_PENDING;
+       handle->event_callback_args.info = (void *)(u_long)ret;
+       EVENT(handle, CS_EVENT_RESET_COMPLETE, CS_EVENT_PRI_LOW);
+    } else {
+       DEBUG(1, ("cs: resetting socket %d\n", i));
+       send_event(s, CS_EVENT_RESET_PHYSICAL, CS_EVENT_PRI_LOW);
+       s->reset_handle = handle;
+       reset_socket(i);
+    }
+    return CS_SUCCESS;
+} /* reset_card */
+
+/*======================================================================
+
+    These shut down or wake up a socket.  They are sort of user
+    initiated versions of the APM suspend and resume actions.
+    
+======================================================================*/
+
+static int suspend_card(client_handle_t handle, client_req_t *req)
+{
+    int i;
+    socket_info_t *s;
+    
+    if (CHECK_HANDLE(handle))
+       return CS_BAD_HANDLE;
+    i = handle->Socket; s = socket_table[i];
+    if (!(s->state & SOCKET_PRESENT))
+       return CS_NO_CARD;
+    if (s->state & SOCKET_SUSPEND)
+       return CS_IN_USE;
+
+    DEBUG(1, ("cs: suspending socket %d\n", i));
+    send_event(s, CS_EVENT_PM_SUSPEND, CS_EVENT_PRI_LOW);
+    s->ss_entry(s->sock, SS_SetSocket, &dead_socket);
+    s->state |= SOCKET_SUSPEND;
+
+    return CS_SUCCESS;
+} /* suspend_card */
+
+static int resume_card(client_handle_t handle, client_req_t *req)
+{
+    int i;
+    socket_info_t *s;
+    
+    if (CHECK_HANDLE(handle))
+       return CS_BAD_HANDLE;
+    i = handle->Socket; s = socket_table[i];
+    if (!(s->state & SOCKET_PRESENT))
+       return CS_NO_CARD;
+    if (!(s->state & SOCKET_SUSPEND))
+       return CS_IN_USE;
+
+    DEBUG(1, ("cs: waking up socket %d\n", i));
+    setup_socket(i);
+
+    return CS_SUCCESS;
+} /* resume_card */
+
+/*======================================================================
+
+    These handle user requests to eject or insert a card.
+    
+======================================================================*/
+
+static int eject_card(client_handle_t handle, client_req_t *req)
+{
+    int i, ret;
+    socket_info_t *s;
+    u_long flags;
+    
+    if (CHECK_HANDLE(handle))
+       return CS_BAD_HANDLE;
+    i = handle->Socket; s = socket_table[i];
+    if (!(s->state & SOCKET_PRESENT))
+       return CS_NO_CARD;
+
+    DEBUG(1, ("cs: user eject request on socket %d\n", i));
+
+    ret = send_event(s, CS_EVENT_EJECTION_REQUEST, CS_EVENT_PRI_LOW);
+    if (ret != 0)
+       return ret;
+
+    spin_lock_irqsave(&s->lock, flags);
+    do_shutdown(s);
+    spin_unlock_irqrestore(&s->lock, flags);
+    
+    return CS_SUCCESS;
+    
+} /* eject_card */
+
+static int insert_card(client_handle_t handle, client_req_t *req)
+{
+    int i, status;
+    socket_info_t *s;
+    u_long flags;
+    
+    if (CHECK_HANDLE(handle))
+       return CS_BAD_HANDLE;
+    i = handle->Socket; s = socket_table[i];
+    if (s->state & SOCKET_PRESENT)
+       return CS_IN_USE;
+
+    DEBUG(1, ("cs: user insert request on socket %d\n", i));
+
+    spin_lock_irqsave(&s->lock, flags);
+    if (!(s->state & SOCKET_SETUP_PENDING)) {
+       s->state |= SOCKET_SETUP_PENDING;
+       spin_unlock_irqrestore(&s->lock, flags);
+       s->ss_entry(i, SS_GetStatus, &status);
+       if (status & SS_DETECT)
+           setup_socket(i);
+       else {
+           s->state &= ~SOCKET_SETUP_PENDING;
+           return CS_NO_CARD;
+       }
+    } else
+       spin_unlock_irqrestore(&s->lock, flags);
+
+    return CS_SUCCESS;
+} /* insert_card */
+
+/*======================================================================
+
+    Maybe this should send a CS_EVENT_CARD_INSERTION event if we
+    haven't sent one to this client yet?
+    
+======================================================================*/
+
+static int set_event_mask(client_handle_t handle, eventmask_t *mask)
+{
+    u_int events, bit;
+    if (CHECK_HANDLE(handle))
+       return CS_BAD_HANDLE;
+    if (handle->Attributes & CONF_EVENT_MASK_VALID)
+       return CS_BAD_SOCKET;
+    handle->EventMask = mask->EventMask;
+    events = handle->PendingEvents & handle->EventMask;
+    handle->PendingEvents -= events;
+    while (events != 0) {
+       bit = ((events ^ (events-1)) + 1) >> 1;
+       EVENT(handle, bit, CS_EVENT_PRI_LOW);
+       events -= bit;
+    }
+    return CS_SUCCESS;
+} /* set_event_mask */
+
+/*====================================================================*/
+
+static int report_error(client_handle_t handle, error_info_t *err)
+{
+    int i;
+    char *serv;
+
+    if (CHECK_HANDLE(handle))
+       printk(KERN_NOTICE);
+    else
+       printk(KERN_NOTICE "%s: ", handle->dev_info);
+    
+    for (i = 0; i < SERVICE_COUNT; i++)
+       if (service_table[i].key == err->func) break;
+    if (i < SERVICE_COUNT)
+       serv = service_table[i].msg;
+    else
+       serv = "Unknown service number";
+
+    for (i = 0; i < ERROR_COUNT; i++)
+       if (error_table[i].key == err->retcode) break;
+    if (i < ERROR_COUNT)
+       printk("%s: %s\n", serv, error_table[i].msg);
+    else
+       printk("%s: Unknown error code %#x\n", serv, err->retcode);
+
+    return CS_SUCCESS;
+} /* report_error */
+
+/*====================================================================*/
+
+int CardServices(int func, void *a1, void *a2, void *a3)
+{
+
+#ifdef PCMCIA_DEBUG
+    if (pc_debug > 1) {
+       int i;
+       for (i = 0; i < SERVICE_COUNT; i++)
+           if (service_table[i].key == func) break;
+       if (i < SERVICE_COUNT)
+           printk(KERN_DEBUG "cs: CardServices(%s, 0x%p, 0x%p)\n",
+                  service_table[i].msg, a1, a2);
+       else
+           printk(KERN_DEBUG "cs: CardServices(Unknown func %d, "
+                  "0x%p, 0x%p)\n", func, a1, a2);
+    }
+#endif
+    switch (func) {
+    case AccessConfigurationRegister:
+       return access_configuration_register(a1, a2); break;
+    case AdjustResourceInfo:
+       return adjust_resource_info(a1, a2); break;
+    case CheckEraseQueue:
+       return check_erase_queue(a1); break;
+    case CloseMemory:
+       return close_memory(a1); break;
+    case CopyMemory:
+       return copy_memory(a1, a2); break;
+    case DeregisterClient:
+       return deregister_client(a1); break;
+    case DeregisterEraseQueue:
+       return deregister_erase_queue(a1); break;
+    case GetFirstClient:
+       return get_first_client(a1, a2); break;
+    case GetCardServicesInfo:
+       return get_card_services_info(a1); break;
+    case GetConfigurationInfo:
+       return get_configuration_info(a1, a2); break;
+    case GetNextClient:
+       return get_next_client(a1, a2); break;
+    case GetFirstRegion:
+       return get_first_region(a1, a2); break;
+    case GetFirstTuple:
+       return get_first_tuple(a1, a2); break;
+    case GetNextRegion:
+       return get_next_region(a1, a2); break;
+    case GetNextTuple:
+       return get_next_tuple(a1, a2); break;
+    case GetStatus:
+       return get_status(a1, a2); break;
+    case GetTupleData:
+       return get_tuple_data(a1, a2); break;
+    case MapMemPage:
+       return map_mem_page(a1, a2); break;
+    case ModifyConfiguration:
+       return modify_configuration(a1, a2); break;
+    case ModifyWindow:
+       return modify_window(a1, a2); break;
+    case OpenMemory:
+       return open_memory(a1, a2);
+    case ParseTuple:
+       return parse_tuple(a1, a2, a3); break;
+    case ReadMemory:
+       return read_memory(a1, a2, a3); break;
+    case RegisterClient:
+       return register_client(a1, a2); break;
+    case RegisterEraseQueue:
+       return register_erase_queue(a1, a2); break;
+    case RegisterMTD:
+       return register_mtd(a1, a2); break;
+    case ReleaseConfiguration:
+       return release_configuration(a1, a2); break;
+    case ReleaseIO:
+       return release_io(a1, a2); break;
+    case ReleaseIRQ:
+       return cs_release_irq(a1, a2); break;
+    case ReleaseWindow:
+       return release_window(a1); break;
+    case RequestConfiguration:
+       return request_configuration(a1, a2); break;
+    case RequestIO:
+       return request_io(a1, a2); break;
+    case RequestIRQ:
+       return cs_request_irq(a1, a2); break;
+    case RequestWindow:
+       return request_window(a1, a2); break;
+    case ResetCard:
+       return reset_card(a1, a2); break;
+    case SetEventMask:
+       return set_event_mask(a1, a2); break;
+    case ValidateCIS:
+       return validate_cis(a1, a2); break;
+    case WriteMemory:
+       return write_memory(a1, a2, a3); break;
+    case BindDevice:
+       return bind_device(a1); break;
+    case BindMTD:
+       return bind_mtd(a1); break;
+    case ReportError:
+       return report_error(a1, a2); break;
+    case SuspendCard:
+       return suspend_card(a1, a2); break;
+    case ResumeCard:
+       return resume_card(a1, a2); break;
+    case EjectCard:
+       return eject_card(a1, a2); break;
+    case InsertCard:
+       return insert_card(a1, a2); break;
+    case ReplaceCIS:
+       return replace_cis(a1, a2); break;
+    default:
+       return CS_UNSUPPORTED_FUNCTION; break;
+    }
+    
+} /* CardServices */
+
+/*======================================================================
+
+    OS-specific module glue goes here
+    
+======================================================================*/
+
+EXPORT_SYMBOL(register_ss_entry);
+EXPORT_SYMBOL(unregister_ss_entry);
+EXPORT_SYMBOL(CardServices);
+EXPORT_SYMBOL(MTDHelperEntry);
+
+static int pcmcia_cs_init(void)
+{
+    printk(KERN_INFO "%s\n", release);
+    printk(KERN_INFO "  %s\n", options);
+    DEBUG(0, ("%s\n", version));
+#ifdef CONFIG_APM
+    if (do_apm)
+       apm_register_callback(&handle_apm_event);
+#endif
+#ifdef CONFIG_PROC_FS
+    proc_pccard = create_proc_entry("pccard", S_IFDIR, proc_bus);
+#endif
+    return 0;
+}
+
+#ifdef MODULE
+
+int init_module(void)
+{
+       return pcmcia_cs_init();
+}
+
+void cleanup_module(void)
+{
+    printk(KERN_INFO "unloading PCMCIA Card Services\n");
+#ifdef CONFIG_PROC_FS
+    if (proc_pccard) {
+       remove_proc_entry("pccard", proc_bus);
+    }
+#endif
+#ifdef CONFIG_APM
+    if (do_apm)
+       apm_unregister_callback(&handle_apm_event);
+#endif
+    release_resource_db();
+}
+
+#else
+
+extern int pcmcia_ds_init(void);
+extern int pcmcia_i82365_init(void);
+
+int pcmcia_init(void)
+{
+       /* Start core services */
+       pcmcia_cs_init();
+
+       /* Load the socket drivers */
+       pcmcia_i82365_init();
+
+       /* Get the ball rolling.. */
+       return pcmcia_ds_init();
+}
+
+#endif
+
+/*====================================================================*/
diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h
new file mode 100644 (file)
index 0000000..6fe9e78
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ * cs_internal.h 1.41 1999/08/28 04:01:47
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ *  are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ */
+
+#ifndef _LINUX_CS_INTERNAL_H
+#define _LINUX_CS_INTERNAL_H
+
+typedef struct erase_busy_t {
+    eraseq_entry_t     *erase;
+    client_handle_t    client;
+    struct timer_list  timeout;
+    struct erase_busy_t        *prev, *next;
+} erase_busy_t;
+
+#define ERASEQ_MAGIC   0xFA67
+typedef struct eraseq_t {
+    u_short            eraseq_magic;
+    client_handle_t    handle;
+    int                        count;
+    eraseq_entry_t     *entry;
+} eraseq_t;
+
+#define CLIENT_MAGIC   0x51E6
+typedef struct client_t {
+    u_short            client_magic;
+    socket_t           Socket;
+    u_char             Function;
+    dev_info_t         dev_info;
+    u_int              Attributes;
+    u_int              state;
+    event_t            EventMask, PendingEvents;
+    int (*event_handler)(event_t event, int priority,
+                        event_callback_args_t *);
+    event_callback_args_t event_callback_args;
+    struct client_t    *next;
+    u_int              mtd_count;
+    wait_queue_head_t  mtd_req;
+    erase_busy_t       erase_busy;
+} client_t;
+
+/* Flags in client state */
+#define CLIENT_CONFIG_LOCKED   0x0001
+#define CLIENT_IRQ_REQ         0x0002
+#define CLIENT_IO_REQ          0x0004
+#define CLIENT_UNBOUND         0x0008
+#define CLIENT_STALE           0x0010
+#define CLIENT_WIN_REQ(i)      (0x20<<(i))
+#define CLIENT_CARDBUS         0x8000
+
+typedef struct io_window_t {
+    u_int              Attributes;
+    ioaddr_t           BasePort, NumPorts;
+    ioaddr_t           InUse, Config;
+} io_window_t;
+
+#define WINDOW_MAGIC   0xB35C
+typedef struct window_t {
+    u_short            magic;
+    u_short            index;
+    client_handle_t    handle;
+    struct socket_info_t *sock;
+    u_long             base;
+    u_long             size;
+    pccard_mem_map     ctl;
+} window_t;
+
+#define REGION_MAGIC   0xE3C9
+typedef struct region_t {
+    u_short            region_magic;
+    u_short            state;
+    dev_info_t         dev_info;
+    client_handle_t    mtd;
+    u_int              MediaID;
+    region_info_t      info;
+} region_t;
+
+#define REGION_STALE   0x01
+
+/* Each card function gets one of these guys */
+typedef struct config_t {
+    u_int              state;
+    u_int              Attributes;
+    u_int              Vcc, Vpp1, Vpp2;
+    u_int              IntType;
+    u_int              ConfigBase;
+    u_char             Status, Pin, Copy, Option, ExtStatus;
+    u_int              Present;
+    u_int              CardValues;
+    io_req_t           io;
+    struct {
+       u_int           Attributes;
+    } irq;
+} config_t;
+
+/* Maximum number of IO windows per socket */
+#define MAX_IO_WIN 2
+
+/* Maximum number of memory windows per socket */
+#define MAX_WIN 4
+
+/* The size of the CIS cache */
+#define MAX_CIS_TABLE  64
+#define MAX_CIS_DATA   512
+
+typedef struct socket_info_t {
+    spinlock_t                 lock;
+    ss_entry_t                 ss_entry;
+    u_int                      sock;
+    socket_state_t             socket;
+    socket_cap_t               cap;
+    u_int                      state;
+    u_short                    functions;
+    u_short                    lock_count;
+    client_handle_t            clients;
+    u_int                      real_clients;
+    client_handle_t            reset_handle;
+    struct timer_list          setup, shutdown;
+    u_long                     unreset_timeout;
+    pccard_mem_map             cis_mem;
+    u_char                     *cis_virt;
+    config_t                   *config;
+#ifdef CONFIG_CARDBUS
+    u_int                      cb_cis_space;
+    cb_bridge_map              cb_cis_map;
+    u_char                     *cb_cis_virt;
+    struct cb_config_t         *cb_config;
+#endif
+    struct {
+       u_int                   AssignedIRQ;
+       u_int                   Config;
+    } irq;
+    io_window_t                        io[MAX_IO_WIN];
+    window_t                   win[MAX_WIN];
+    region_t                   *c_region, *a_region;
+    erase_busy_t               erase_busy;
+    int                                cis_used;
+    struct {
+       u_int                   addr;
+       u_short                 len;
+       u_short                 attr;
+    }                          cis_table[MAX_CIS_TABLE];
+    char                       cis_cache[MAX_CIS_DATA];
+    u_int                      fake_cis_len;
+    char                       *fake_cis;
+#ifdef CONFIG_PROC_FS
+    struct proc_dir_entry      *proc;
+#endif
+} socket_info_t;
+
+/* Flags in config state */
+#define CONFIG_LOCKED          0x01
+#define CONFIG_IRQ_REQ         0x02
+#define CONFIG_IO_REQ          0x04
+
+/* Flags in socket state */
+#define SOCKET_PRESENT         0x0008
+#define SOCKET_SETUP_PENDING   0x0010
+#define SOCKET_SHUTDOWN_PENDING        0x0020
+#define SOCKET_RESET_PENDING   0x0040
+#define SOCKET_SUSPEND         0x0080
+#define SOCKET_WIN_REQ(i)      (0x0100<<(i))
+#define SOCKET_IO_REQ(i)       (0x1000<<(i))
+#define SOCKET_REGION_INFO     0x4000
+#define SOCKET_CARDBUS         0x8000
+
+#define CHECK_HANDLE(h) \
+    (((h) == NULL) || ((h)->client_magic != CLIENT_MAGIC))
+
+#define CHECK_SOCKET(s) \
+    (((s) >= sockets) || (socket_table[s]->ss_entry == NULL))
+
+#define SOCKET(h) (socket_table[(h)->Socket])
+#define CONFIG(h) (&SOCKET(h)->config[(h)->Function])
+
+#define CHECK_REGION(r) \
+    (((r) == NULL) || ((r)->region_magic != REGION_MAGIC))
+
+#define CHECK_ERASEQ(q) \
+    (((q) == NULL) || ((q)->eraseq_magic != ERASEQ_MAGIC))
+
+#define EVENT(h, e, p) \
+    ((h)->event_handler((e), (p), &(h)->event_callback_args))
+
+/* In cardbus.c */
+int cb_config(socket_info_t *s);
+void cb_release(socket_info_t *s);
+void cb_enable(socket_info_t *s);
+void cb_disable(socket_info_t *s);
+void read_cb_mem(socket_info_t *s, u_char fn, int space,
+                u_int addr, u_int len, void *ptr);
+int cb_setup_cis_mem(socket_info_t *s, int space);
+void cb_release_cis_mem(socket_info_t *s);
+
+/* In cistpl.c */
+void read_cis_mem(socket_info_t *s, int attr,
+                 u_int addr, u_int len, void *ptr);
+void write_cis_mem(socket_info_t *s, int attr,
+                  u_int addr, u_int len, void *ptr);
+int setup_cis_mem(socket_info_t *s);
+void release_cis_mem(socket_info_t *s);
+int verify_cis_cache(socket_info_t *s);
+void preload_cis_cache(socket_info_t *s);
+int get_first_tuple(client_handle_t handle, tuple_t *tuple);
+int get_next_tuple(client_handle_t handle, tuple_t *tuple);
+int get_tuple_data(client_handle_t handle, tuple_t *tuple);
+int parse_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse);
+int validate_cis(client_handle_t handle, cisinfo_t *info);
+int replace_cis(client_handle_t handle, cisdump_t *cis);
+int read_tuple(client_handle_t handle, cisdata_t code, void *parse);
+
+/* In bulkmem.c */
+void retry_erase_list(struct erase_busy_t *list, u_int cause);
+int get_first_region(client_handle_t handle, region_info_t *rgn);
+int get_next_region(client_handle_t handle, region_info_t *rgn);
+int register_mtd(client_handle_t handle, mtd_reg_t *reg);
+int register_erase_queue(client_handle_t *handle, eraseq_hdr_t *header);
+int deregister_erase_queue(eraseq_handle_t eraseq);
+int check_erase_queue(eraseq_handle_t eraseq);
+int open_memory(client_handle_t *handle, open_mem_t *open);
+int close_memory(memory_handle_t handle);
+int read_memory(memory_handle_t handle, mem_op_t *req, caddr_t buf);
+int write_memory(memory_handle_t handle, mem_op_t *req, caddr_t buf);
+int copy_memory(memory_handle_t handle, copy_op_t *req);
+
+/* In rsrc_mgr */
+void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long),
+                 int force_low);
+int find_io_region(ioaddr_t *base, ioaddr_t num, char *name);
+int find_mem_region(u_long *base, u_long num, char *name,
+                   u_long align, int force_low);
+int try_irq(u_int Attributes, int irq, int specific);
+void undo_irq(u_int Attributes, int irq);
+int adjust_resource_info(client_handle_t handle, adjust_t *adj);
+void release_resource_db(void);
+int proc_read_io(char *buf, char **start, off_t pos,
+                int count, int *eof, void *data);
+int proc_read_mem(char *buf, char **start, off_t pos,
+                 int count, int *eof, void *data);
+
+/* in pnp components */
+int proc_read_irq(char *buf, char **start, off_t pos,
+                 int count, int *eof, void *data);
+void pnp_bios_init(void);
+void pnp_proc_init(void);
+void pnp_proc_done(void);
+void pnp_rsrc_init(void);
+void pnp_rsrc_done(void);
+
+#define MAX_SOCK 8
+extern socket_t sockets;
+extern socket_info_t *socket_table[MAX_SOCK];
+
+#ifdef CONFIG_PROC_FS
+extern struct proc_dir_entry *proc_pccard;
+#endif
+
+#ifdef PCMCIA_DEBUG
+#define _printk(args...) printk(KERN_DEBUG args)
+extern int pc_debug;
+#define DEBUG(n, args) do { if (pc_debug>(n)) _printk args; } while (0)
+#else
+#define DEBUG(n, args) do { } while (0)
+#endif
+
+#endif /* _LINUX_CS_INTERNAL_H */
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
new file mode 100644 (file)
index 0000000..5f77be7
--- /dev/null
@@ -0,0 +1,885 @@
+/*======================================================================
+
+    PC Card Driver Services
+    
+    ds.c 1.95 1999/08/28 04:01:46
+    
+    The contents of this file are subject to the Mozilla Public
+    License Version 1.1 (the "License"); you may not use this file
+    except in compliance with the License. You may obtain a copy of
+    the License at http://www.mozilla.org/MPL/
+
+    Software distributed under the License is distributed on an "AS
+    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+    implied. See the License for the specific language governing
+    rights and limitations under the License.
+
+    The initial developer of the original code is David A. Hinds
+    <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+
+    Alternatively, the contents of this file may be used under the
+    terms of the GNU Public License version 2 (the "GPL"), in which
+    case the provisions of the GPL are applicable instead of the
+    above.  If you wish to allow the use of your version of this file
+    only under the terms of the GPL and not to allow others to use
+    your version of this file under the MPL, indicate your decision
+    by deleting the provisions above and replace them with the notice
+    and other provisions required by the GPL.  If you do not delete
+    the provisions above, a recipient may use your version of this
+    file under either the MPL or the GPL.
+    
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/fcntl.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/ioctl.h>
+#include <linux/poll.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/bulkmem.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+
+#ifdef PCMCIA_DEBUG
+int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+static const char *version =
+"ds.c 1.95 1999/08/28 04:01:46 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*====================================================================*/
+
+typedef struct driver_info_t {
+    dev_info_t         dev_info;
+    int                        use_count;
+    dev_link_t         *(*attach)(void);
+    void               (*detach)(dev_link_t *);
+    struct driver_info_t *next;
+} driver_info_t;
+
+typedef struct socket_bind_t {
+    driver_info_t      *driver;
+    dev_link_t         *instance;
+    struct socket_bind_t *next;
+} socket_bind_t;
+
+/* Device user information */
+#define MAX_EVENTS     32
+#define USER_MAGIC     0x7ea4
+#define CHECK_USER(u) \
+    (((u) == NULL) || ((u)->user_magic != USER_MAGIC))
+typedef struct user_info_t {
+    u_int              user_magic;
+    int                        event_head, event_tail;
+    event_t            event[MAX_EVENTS];
+    struct user_info_t *next;
+} user_info_t;
+
+/* Socket state information */
+typedef struct socket_info_t {
+    client_handle_t    handle;
+    int                        state;
+    user_info_t                *user;
+    int                        req_pending, req_result;
+    wait_queue_head_t  queue, request;
+    struct timer_list  removal;
+    socket_bind_t      *bind;
+} socket_info_t;
+
+#define SOCKET_PRESENT         0x01
+#define SOCKET_BUSY            0x02
+#define SOCKET_REMOVAL_PENDING 0x10
+
+/*====================================================================*/
+
+/* Device driver ID passed to Card Services */
+static dev_info_t dev_info = "Driver Services";
+
+/* Linked list of all registered device drivers */
+static driver_info_t *root_driver = NULL;
+
+static int sockets = 0, major_dev = -1;
+static socket_info_t *socket_table = NULL;
+
+/*====================================================================*/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+    error_info_t err = { func, ret };
+    CardServices(ReportError, handle, &err);
+}
+
+/*======================================================================
+
+    Register_pccard_driver() and unregister_pccard_driver() are used
+    tell Driver Services that a PC Card client driver is available to
+    be bound to sockets.
+    
+======================================================================*/
+
+int register_pccard_driver(dev_info_t *dev_info,
+                          dev_link_t *(*attach)(void),
+                          void (*detach)(dev_link_t *))
+{
+    driver_info_t *driver;
+    socket_bind_t *b;
+    int i;
+
+    DEBUG(0, "ds: register_pccard_driver('%s')\n", (char *)dev_info);
+    for (driver = root_driver; driver; driver = driver->next)
+       if (strncmp((char *)dev_info, (char *)driver->dev_info,
+                   DEV_NAME_LEN) == 0)
+           break;
+    if (!driver) {
+       driver = kmalloc(sizeof(driver_info_t), GFP_KERNEL);
+       strncpy(driver->dev_info, (char *)dev_info, DEV_NAME_LEN);
+       driver->use_count = 0;
+       driver->next = root_driver;
+       root_driver = driver;
+    }
+
+    driver->attach = attach;
+    driver->detach = detach;
+    if (driver->use_count == 0) return 0;
+    
+    /* Instantiate any already-bound devices */
+    for (i = 0; i < sockets; i++)
+       for (b = socket_table[i].bind; b; b = b->next) {
+           if (b->driver != driver) continue;
+           b->instance = driver->attach();
+           if (b->instance == NULL)
+               printk(KERN_NOTICE "ds: unable to create instance "
+                      "of '%s'!\n", driver->dev_info);
+       }
+    
+    return 0;
+} /* register_pccard_driver */
+
+/*====================================================================*/
+
+int unregister_pccard_driver(dev_info_t *dev_info)
+{
+    driver_info_t *target, **d = &root_driver;
+    socket_bind_t *b;
+    int i;
+    
+    DEBUG(0, "ds: unregister_pccard_driver('%s')\n",
+         (char *)dev_info);
+    while ((*d) && (strncmp((*d)->dev_info, (char *)dev_info,
+                           DEV_NAME_LEN) != 0))
+       d = &(*d)->next;
+    if (*d == NULL)
+       return -1;
+    
+    target = *d;
+    if (target->use_count == 0) {
+       *d = target->next;
+       kfree(target);
+    } else {
+       /* Blank out any left-over device instances */
+       target->attach = NULL; target->detach = NULL;
+       for (i = 0; i < sockets; i++)
+           for (b = socket_table[i].bind; b; b = b->next)
+               if (b->driver == target) b->instance = NULL;
+    }
+    return 0;
+} /* unregister_pccard_driver */
+
+/*======================================================================
+
+    These manage a ring buffer of events pending for one user process
+    
+======================================================================*/
+
+static int queue_empty(user_info_t *user)
+{
+    return (user->event_head == user->event_tail);
+}
+
+static event_t get_queued_event(user_info_t *user)
+{
+    user->event_tail = (user->event_tail+1) % MAX_EVENTS;
+    return user->event[user->event_tail];
+}
+
+static void queue_event(user_info_t *user, event_t event)
+{
+    user->event_head = (user->event_head+1) % MAX_EVENTS;
+    if (user->event_head == user->event_tail)
+       user->event_tail = (user->event_tail+1) % MAX_EVENTS;
+    user->event[user->event_head] = event;
+}
+
+static void handle_event(socket_info_t *s, event_t event)
+{
+    user_info_t *user;
+    for (user = s->user; user; user = user->next)
+       queue_event(user, event);
+    wake_up_interruptible(&s->queue);
+}
+
+static int handle_request(socket_info_t *s, event_t event)
+{
+    if (s->req_pending != 0)
+       return CS_IN_USE;
+    if (s->state & SOCKET_BUSY)
+       s->req_pending = 1;
+    handle_event(s, event);
+    if (s->req_pending > 0) {
+       interruptible_sleep_on(&s->request);
+       if (signal_pending(current))
+           return CS_IN_USE;
+       else
+           return s->req_result;
+    }
+    return CS_SUCCESS;
+}
+
+static void handle_removal(u_long sn)
+{
+    socket_info_t *s = &socket_table[sn];
+    handle_event(s, CS_EVENT_CARD_REMOVAL);
+    s->state &= ~SOCKET_REMOVAL_PENDING;
+}
+
+/*======================================================================
+
+    The card status event handler.
+    
+======================================================================*/
+
+static int ds_event(event_t event, int priority,
+                   event_callback_args_t *args)
+{
+    socket_info_t *s;
+    int i;
+
+    DEBUG(1, "ds: ds_event(0x%06x, %d, 0x%p)\n",
+         event, priority, args->client_handle);
+    s = args->client_data;
+    i = s - socket_table;
+    
+    switch (event) {
+       
+    case CS_EVENT_CARD_REMOVAL:
+       s->state &= ~SOCKET_PRESENT;
+       if (!(s->state & SOCKET_REMOVAL_PENDING)) {
+           s->state |= SOCKET_REMOVAL_PENDING;
+           s->removal.expires = jiffies + HZ/10;
+           add_timer(&s->removal);
+       }
+       break;
+       
+    case CS_EVENT_CARD_INSERTION:
+       s->state |= SOCKET_PRESENT;
+       handle_event(s, event);
+       break;
+
+    case CS_EVENT_EJECTION_REQUEST:
+       return handle_request(s, event);
+       break;
+       
+    default:
+       handle_event(s, event);
+       break;
+    }
+
+    return 0;
+} /* ds_event */
+
+/*======================================================================
+
+    bind_mtd() connects a memory region with an MTD client.
+    
+======================================================================*/
+
+static int bind_mtd(int i, mtd_info_t *mtd_info)
+{
+    mtd_bind_t bind_req;
+    int ret;
+
+    bind_req.dev_info = &mtd_info->dev_info;
+    bind_req.Attributes = mtd_info->Attributes;
+    bind_req.Socket = i;
+    bind_req.CardOffset = mtd_info->CardOffset;
+    ret = CardServices(BindMTD, &bind_req);
+    if (ret != CS_SUCCESS) {
+       cs_error(NULL, BindMTD, ret);
+       printk(KERN_NOTICE "ds: unable to bind MTD '%s' to socket %d"
+              " offset 0x%x\n",
+              (char *)bind_req.dev_info, i, bind_req.CardOffset);
+       return -ENODEV;
+    }
+    return 0;
+} /* bind_mtd */
+
+/*======================================================================
+
+    bind_request() connects a socket to a particular client driver.
+    It looks up the specified device ID in the list of registered
+    drivers, binds it to the socket, and tries to create an instance
+    of the device.  unbind_request() deletes a driver instance.
+    
+======================================================================*/
+
+static int bind_request(int i, bind_info_t *bind_info)
+{
+    struct driver_info_t *driver;
+    socket_bind_t *b;
+    bind_req_t bind_req;
+    socket_info_t *s = &socket_table[i];
+    int ret;
+
+    DEBUG(2, "bind_request(%d, '%s')\n", i,
+         (char *)bind_info->dev_info);
+    for (driver = root_driver; driver; driver = driver->next)
+       if (strcmp((char *)driver->dev_info,
+                  (char *)bind_info->dev_info) == 0)
+           break;
+    if (driver == NULL) {
+       driver = kmalloc(sizeof(driver_info_t), GFP_KERNEL);
+       strncpy(driver->dev_info, bind_info->dev_info, DEV_NAME_LEN);
+       driver->use_count = 0;
+       driver->next = root_driver;
+       driver->attach = NULL; driver->detach = NULL;
+       root_driver = driver;
+    }
+
+    for (b = s->bind; b; b = b->next)
+       if (driver == b->driver)
+           break;
+    if (b != NULL) {
+       bind_info->instance = b->instance;
+       return -EBUSY;
+    }
+
+    bind_req.Socket = i;
+    bind_req.Function = bind_info->function;
+    bind_req.dev_info = &driver->dev_info;
+    ret = CardServices(BindDevice, &bind_req);
+    if (ret != CS_SUCCESS) {
+       cs_error(NULL, BindDevice, ret);
+       printk(KERN_NOTICE "ds: unable to bind '%s' to socket %d\n",
+              (char *)dev_info, i);
+       return -ENODEV;
+    }
+
+    /* Add binding to list for this socket */
+    driver->use_count++;
+    b = kmalloc(sizeof(socket_bind_t), GFP_KERNEL);
+    b->driver = driver;
+    b->instance = NULL;
+    b->next = s->bind;
+    s->bind = b;
+    
+    if (driver->attach) {
+       b->instance = driver->attach();
+       if (b->instance == NULL) {
+           printk(KERN_NOTICE "ds: unable to create instance "
+                  "of '%s'!\n", (char *)bind_info->dev_info);
+           return -ENODEV;
+       }
+    }
+    
+    return 0;
+} /* bind_request */
+
+/*====================================================================*/
+
+static int get_device_info(int i, bind_info_t *bind_info, int first)
+{
+    socket_info_t *s = &socket_table[i];
+    socket_bind_t *b;
+    dev_node_t *node;
+    
+    for (b = s->bind; b; b = b->next)
+       if (strcmp((char *)b->driver->dev_info,
+                  (char *)bind_info->dev_info) == 0)
+           break;
+    if (b == NULL) return -ENODEV;
+    if ((b->instance == NULL) ||
+       (b->instance->state & DEV_CONFIG_PENDING))
+       return -EAGAIN;
+    if (first)
+       node = b->instance->dev;
+    else
+       for (node = b->instance->dev; node; node = node->next)
+           if (node == bind_info->next) break;
+    if (node == NULL) return -ENODEV;
+
+    strncpy(bind_info->name, node->dev_name, DEV_NAME_LEN);
+    bind_info->name[DEV_NAME_LEN-1] = '\0';
+    bind_info->major = node->major;
+    bind_info->minor = node->minor;
+    bind_info->next = node->next;
+    
+    return 0;
+} /* get_device_info */
+
+/*====================================================================*/
+
+static int unbind_request(int i, bind_info_t *bind_info)
+{
+    socket_info_t *s = &socket_table[i];
+    socket_bind_t **b, *c;
+
+    DEBUG(2, "unbind_request(%d, '%s')\n", i,
+         (char *)bind_info->dev_info);
+    for (b = &s->bind; *b; b = &(*b)->next)
+       if (strcmp((char *)(*b)->driver->dev_info,
+                  (char *)bind_info->dev_info) == 0)
+           break;
+    if (*b == NULL)
+       return -ENODEV;
+    
+    c = *b;
+    c->driver->use_count--;
+    if (c->driver->detach) {
+       if (c->instance)
+           c->driver->detach(c->instance);
+    } else {
+       if (c->driver->use_count == 0) {
+           driver_info_t **d;
+           for (d = &root_driver; *d; d = &((*d)->next))
+               if (c->driver == *d) break;
+           *d = (*d)->next;
+           kfree_s(c->driver, sizeof(driver_info_t));
+       }
+    }
+    *b = c->next;
+    kfree_s(c, sizeof(socket_bind_t));
+    
+    return 0;
+} /* unbind_request */
+
+/*======================================================================
+
+    The user-mode PC Card device interface
+
+======================================================================*/
+
+static int ds_open(struct inode *inode, struct file *file)
+{
+    socket_t i = MINOR(inode->i_rdev);
+    socket_info_t *s;
+    user_info_t *user;
+
+    DEBUG(0, "ds_open(socket %d)\n", i);
+    if ((i >= sockets) || (sockets == 0))
+       return -ENODEV;
+    s = &socket_table[i];
+    if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
+       if (s->state & SOCKET_BUSY)
+           return -EBUSY;
+       else
+           s->state |= SOCKET_BUSY;
+    }
+    
+    MOD_INC_USE_COUNT;
+    user = kmalloc(sizeof(user_info_t), GFP_KERNEL);
+    user->event_tail = user->event_head = 0;
+    user->next = s->user;
+    user->user_magic = USER_MAGIC;
+    s->user = user;
+    file->private_data = user;
+    
+    if (s->state & SOCKET_PRESENT)
+       queue_event(user, CS_EVENT_CARD_INSERTION);
+    return 0;
+} /* ds_open */
+
+/*====================================================================*/
+
+static int ds_release(struct inode *inode, struct file *file)
+{
+    socket_t i = MINOR(inode->i_rdev);
+    socket_info_t *s;
+    user_info_t *user, **link;
+
+    DEBUG(0, "ds_release(socket %d)\n", i);
+    if ((i >= sockets) || (sockets == 0))
+       return 0;
+    s = &socket_table[i];
+    user = file->private_data;
+    if (CHECK_USER(user))
+       return 0;
+
+    /* Unlink user data structure */
+    if ((file->f_flags & O_ACCMODE) != O_RDONLY)
+       s->state &= ~SOCKET_BUSY;
+    file->private_data = NULL;
+    for (link = &s->user; *link; link = &(*link)->next)
+       if (*link == user) break;
+    if (link == NULL)
+       return 0;
+    *link = user->next;
+    user->user_magic = 0;
+    kfree_s(user, sizeof(user_info_t));
+    
+    MOD_DEC_USE_COUNT;
+    return 0;
+} /* ds_release */
+
+/*====================================================================*/
+
+static ssize_t ds_read(struct file *file, char *buf,
+                             size_t count, loff_t *ppos)
+{
+    socket_t i = MINOR(file->f_dentry->d_inode->i_rdev);
+    socket_info_t *s;
+    user_info_t *user;
+
+    DEBUG(2, "ds_read(socket %d)\n", i);
+    
+    if ((i >= sockets) || (sockets == 0))
+       return -ENODEV;
+    if (count < 4)
+       return -EINVAL;
+    s = &socket_table[i];
+    user = file->private_data;
+    if (CHECK_USER(user))
+       return -EIO;
+    
+    if (queue_empty(user)) {
+       interruptible_sleep_on(&s->queue);
+       if (signal_pending(current))
+           return -EINTR;
+    }
+    put_user(get_queued_event(user), (int *)buf);
+    return 4;
+} /* ds_read */
+
+/*====================================================================*/
+
+static ssize_t ds_write(struct file *file, const char *buf,
+                              size_t count, loff_t *ppos)
+{
+    socket_t i = MINOR(file->f_dentry->d_inode->i_rdev);
+    socket_info_t *s;
+    user_info_t *user;
+
+    DEBUG(2, "ds_write(socket %d)\n", i);
+    
+    if ((i >= sockets) || (sockets == 0))
+       return -ENODEV;
+    if (count != 4)
+       return -EINVAL;
+    if ((file->f_flags & O_ACCMODE) == O_RDONLY)
+       return -EBADF;
+    s = &socket_table[i];
+    user = file->private_data;
+    if (CHECK_USER(user))
+       return -EIO;
+
+    if (s->req_pending) {
+       s->req_pending--;
+       get_user(s->req_result, (int *)buf);
+       if ((s->req_result != 0) || (s->req_pending == 0))
+           wake_up_interruptible(&s->request);
+    } else
+       return -EIO;
+
+    return 4;
+} /* ds_write */
+
+/*====================================================================*/
+
+static u_int ds_poll(struct file *file, poll_table *wait)
+{
+    socket_t i = MINOR(file->f_dentry->d_inode->i_rdev);
+    socket_info_t *s;
+    user_info_t *user;
+
+    DEBUG(2, "ds_poll(socket %d)\n", i);
+    
+    if ((i >= sockets) || (sockets == 0))
+       return POLLERR;
+    s = &socket_table[i];
+    user = file->private_data;
+    if (CHECK_USER(user))
+       return POLLERR;
+    poll_wait(file, &s->queue, wait);
+    if (!queue_empty(user))
+       return POLLIN | POLLRDNORM;
+    return 0;
+} /* ds_poll */
+
+/*====================================================================*/
+
+static int ds_ioctl(struct inode * inode, struct file * file,
+                   u_int cmd, u_long arg)
+{
+    socket_t i = MINOR(inode->i_rdev);
+    socket_info_t *s;
+    u_int size;
+    int ret, err;
+    ds_ioctl_arg_t buf;
+
+    DEBUG(2, "ds_ioctl(socket %d, %#x, %#lx)\n", i, cmd, arg);
+    
+    if ((i >= sockets) || (sockets == 0))
+       return -ENODEV;
+    s = &socket_table[i];
+    
+    size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
+    if (size > sizeof(ds_ioctl_arg_t)) return -EINVAL;
+
+    /* Permission check */
+    if (!(cmd & IOC_OUT) && !suser())
+       return -EPERM;
+       
+    if (cmd & IOC_IN) {
+       err = verify_area(VERIFY_READ, (char *)arg, size);
+       if (err) {
+           DEBUG(3, "ds_ioctl(): verify_read = %d\n", err);
+           return err;
+       }
+    }
+    if (cmd & IOC_OUT) {
+       err = verify_area(VERIFY_WRITE, (char *)arg, size);
+       if (err) {
+           DEBUG(3, "ds_ioctl(): verify_write = %d\n", err);
+           return err;
+       }
+    }
+    
+    err = ret = 0;
+    
+    if (cmd & IOC_IN) copy_from_user((char *)&buf, (char *)arg, size);
+    
+    switch (cmd) {
+    case DS_ADJUST_RESOURCE_INFO:
+       ret = CardServices(AdjustResourceInfo, s->handle, &buf.adjust);
+       break;
+    case DS_GET_CARD_SERVICES_INFO:
+       ret = CardServices(GetCardServicesInfo, &buf.servinfo);
+       break;
+    case DS_GET_CONFIGURATION_INFO:
+       ret = CardServices(GetConfigurationInfo, s->handle, &buf.config);
+       break;
+    case DS_GET_FIRST_TUPLE:
+       ret = CardServices(GetFirstTuple, s->handle, &buf.tuple);
+       break;
+    case DS_GET_NEXT_TUPLE:
+       ret = CardServices(GetNextTuple, s->handle, &buf.tuple);
+       break;
+    case DS_GET_TUPLE_DATA:
+       buf.tuple.TupleData = buf.tuple_parse.data;
+       buf.tuple.TupleDataMax = sizeof(buf.tuple_parse.data);
+       ret = CardServices(GetTupleData, s->handle, &buf.tuple);
+       break;
+    case DS_PARSE_TUPLE:
+       buf.tuple.TupleData = buf.tuple_parse.data;
+       ret = CardServices(ParseTuple, s->handle, &buf.tuple,
+                          &buf.tuple_parse.parse);
+       break;
+    case DS_RESET_CARD:
+       ret = CardServices(ResetCard, s->handle, NULL);
+       break;
+    case DS_GET_STATUS:
+       ret = CardServices(GetStatus, s->handle, &buf.status);
+       break;
+    case DS_VALIDATE_CIS:
+       ret = CardServices(ValidateCIS, s->handle, &buf.cisinfo);
+       break;
+    case DS_SUSPEND_CARD:
+       ret = CardServices(SuspendCard, s->handle, NULL);
+       break;
+    case DS_RESUME_CARD:
+       ret = CardServices(ResumeCard, s->handle, NULL);
+       break;
+    case DS_EJECT_CARD:
+       ret = CardServices(EjectCard, s->handle, NULL);
+       break;
+    case DS_INSERT_CARD:
+       ret = CardServices(InsertCard, s->handle, NULL);
+       break;
+    case DS_ACCESS_CONFIGURATION_REGISTER:
+       if ((buf.conf_reg.Action == CS_WRITE) && !suser())
+           return -EPERM;
+       ret = CardServices(AccessConfigurationRegister, s->handle,
+                          &buf.conf_reg);
+       break;
+    case DS_GET_FIRST_REGION:
+        ret = CardServices(GetFirstRegion, s->handle, &buf.region);
+       break;
+    case DS_GET_NEXT_REGION:
+       ret = CardServices(GetNextRegion, s->handle, &buf.region);
+       break;
+    case DS_REPLACE_CIS:
+       ret = CardServices(ReplaceCIS, s->handle, &buf.cisdump);
+       break;
+    case DS_BIND_REQUEST:
+       if (!suser()) return -EPERM;
+       err = bind_request(i, &buf.bind_info);
+       break;
+    case DS_GET_DEVICE_INFO:
+       err = get_device_info(i, &buf.bind_info, 1);
+       break;
+    case DS_GET_NEXT_DEVICE:
+       err = get_device_info(i, &buf.bind_info, 0);
+       break;
+    case DS_UNBIND_REQUEST:
+       err = unbind_request(i, &buf.bind_info);
+       break;
+    case DS_BIND_MTD:
+       if (!suser()) return -EPERM;
+       err = bind_mtd(i, &buf.mtd_info);
+       break;
+    default:
+       err = -EINVAL;
+    }
+    
+    if ((err == 0) && (ret != CS_SUCCESS)) {
+       DEBUG(2, "ds_ioctl: ret = %d\n", ret);
+       switch (ret) {
+       case CS_BAD_SOCKET: case CS_NO_CARD:
+           err = -ENODEV; break;
+       case CS_BAD_ARGS: case CS_BAD_ATTRIBUTE: case CS_BAD_IRQ:
+       case CS_BAD_TUPLE:
+           err = -EINVAL; break;
+       case CS_IN_USE:
+           err = -EBUSY; break;
+       case CS_OUT_OF_RESOURCE:
+           err = -ENOSPC; break;
+       case CS_NO_MORE_ITEMS:
+           err = -ENODATA; break;
+       case CS_UNSUPPORTED_FUNCTION:
+           err = -ENOSYS; break;
+       default:
+           err = -EIO; break;
+       }
+    }
+    
+    if (cmd & IOC_OUT) copy_to_user((char *)arg, (char *)&buf, size);
+     
+    return err;
+} /* ds_ioctl */
+
+/*====================================================================*/
+
+static struct file_operations ds_fops = {
+    NULL,              /* lseek */
+    ds_read,           /* read */
+    ds_write,          /* write */
+    NULL,              /* readdir */
+    ds_poll,           /* poll */
+    ds_ioctl,          /* ioctl */
+    NULL,              /* mmap */
+    ds_open,           /* open */
+    NULL,              /* flush */
+    ds_release,                /* release */
+    NULL               /* fsync */
+};
+
+EXPORT_SYMBOL(register_pccard_driver);
+EXPORT_SYMBOL(unregister_pccard_driver);
+
+/*====================================================================*/
+
+int pcmcia_ds_init(void)
+{
+    client_reg_t client_reg;
+    servinfo_t serv;
+    bind_req_t bind;
+    socket_info_t *s;
+    int i, ret;
+    
+    DEBUG(0, "%s\n", version);
+    
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+       printk(KERN_NOTICE "ds: Card Services release does not match!\n");
+       return -1;
+    }
+    if (serv.Count == 0) {
+       printk(KERN_NOTICE "ds: no socket drivers loaded!\n");
+       return -1;
+    }
+    
+    sockets = serv.Count;
+    socket_table = kmalloc(sockets*sizeof(socket_info_t), GFP_KERNEL);
+    for (i = 0, s = socket_table; i < sockets; i++, s++) {
+       s->state = 0;
+       s->user = NULL;
+       s->req_pending = 0;
+       init_waitqueue_head(&s->queue);
+       init_waitqueue_head(&s->request);
+       s->handle = NULL;
+       s->removal.prev = s->removal.next = NULL;
+       s->removal.data = i;
+       s->removal.function = &handle_removal;
+       s->bind = NULL;
+    }
+    
+    /* Set up hotline to Card Services */
+    client_reg.dev_info = bind.dev_info = &dev_info;
+    client_reg.Attributes = INFO_MASTER_CLIENT;
+    client_reg.EventMask =
+       CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+       CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+       CS_EVENT_EJECTION_REQUEST | CS_EVENT_INSERTION_REQUEST |
+        CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+    client_reg.event_handler = &ds_event;
+    client_reg.Version = 0x0210;
+    for (i = 0; i < sockets; i++) {
+       bind.Socket = i;
+       bind.Function = BIND_FN_ALL;
+       ret = CardServices(BindDevice, &bind);
+       if (ret != CS_SUCCESS) {
+           cs_error(NULL, BindDevice, ret);
+           break;
+       }
+       client_reg.event_callback_args.client_data = &socket_table[i];
+       ret = CardServices(RegisterClient, &socket_table[i].handle,
+                          &client_reg);
+       if (ret != CS_SUCCESS) {
+           cs_error(NULL, RegisterClient, ret);
+           break;
+       }
+    }
+    
+    /* Set up character device for user mode clients */
+    i = register_chrdev(0, "pcmcia", &ds_fops);
+    if (i == -EBUSY)
+       printk(KERN_NOTICE "unable to find a free device # for "
+              "Driver Services\n");
+    else
+       major_dev = i;
+    
+    return 0;
+}
+
+#ifdef MODULE
+
+static int init_module(void)
+{
+       return pcmcia_ds_init();
+}
+
+void cleanup_module(void)
+{
+    int i;
+    if (major_dev != -1)
+       unregister_chrdev(major_dev, "pcmcia");
+    for (i = 0; i < sockets; i++)
+       CardServices(DeregisterClient, socket_table[i].handle);
+    sockets = 0;
+    kfree(socket_table);
+}
+
+#endif
diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c
new file mode 100644 (file)
index 0000000..d57cc91
--- /dev/null
@@ -0,0 +1,2811 @@
+/*======================================================================
+
+    Device driver for Intel 82365 and compatible PC Card controllers,
+    and Yenta-compatible PCI-to-CardBus controllers.
+
+    i82365.c $Revision: 1.249 $ $Date: 1999/08/28 04:01:46 $
+
+    The contents of this file are subject to the Mozilla Public
+    License Version 1.1 (the "License"); you may not use this file
+    except in compliance with the License. You may obtain a copy of
+    the License at http://www.mozilla.org/MPL/
+
+    Software distributed under the License is distributed on an "AS
+    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+    implied. See the License for the specific language governing
+    rights and limitations under the License.
+
+    The initial developer of the original code is David A. Hinds
+    <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+
+    Alternatively, the contents of this file may be used under the
+    terms of the GNU Public License version 2 (the "GPL"), in which
+    case the provisions of the GPL are applicable instead of the
+    above.  If you wish to allow the use of your version of this file
+    only under the terms of the GPL and not to allow others to use
+    your version of this file under the MPL, indicate your decision
+    by deleting the provisions above and replace them with the notice
+    and other provisions required by the GPL.  If you do not delete
+    the provisions above, a recipient may use your version of this
+    file under either the MPL or the GPL.
+    
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/proc_fs.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/bitops.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/cs.h>
+
+/* ISA-bus controllers */
+#include "i82365.h"
+#include "cirrus.h"
+#include "vg468.h"
+#include "ricoh.h"
+#include "o2micro.h"
+
+/* PCI-bus controllers */
+#include "yenta.h"
+#include "ti113x.h"
+#include "smc34c90.h"
+#include "topic.h"
+
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+#define DEBUG(n, args) do { if (pc_debug>(n)) printk(KERN_DEBUG args); } while (0)
+static const char *version =
+"i82365.c $Revision: 1.249 $ $Date: 1999/08/28 04:01:46 $ (David Hinds)";
+#else
+#define DEBUG(n, args) do { } while (0)
+#endif
+
+static void irq_count(int, void *, struct pt_regs *);
+static inline int _check_irq(int irq, int flags)
+{
+    if (request_irq(irq, irq_count, flags, "x", NULL) == 0) {
+       free_irq(irq, NULL);
+       return 0;
+    }
+    return -1;
+}
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+#ifdef CONFIG_ISA
+/* Default base address for i82365sl and other ISA chips */
+static int i365_base = 0x3e0;
+/* Should we probe at 0x3e2 for an extra ISA controller? */
+static int extra_sockets = 0;
+/* Specify a socket number to ignore */
+static int ignore = -1;
+/* Bit map or list of interrupts to choose from */
+static u_int irq_mask = 0xffff;
+static int irq_list[16] = { -1 };
+/* The card status change interrupt -- 0 means autoselect */
+static int cs_irq = 0;
+#endif
+
+/* Probe for safe interrupts? */
+static int do_scan = 1;
+/* Poll status interval -- 0 means default to interrupt */
+static int poll_interval = 0;
+/* External clock time, in nanoseconds.  120 ns = 8.33 MHz */
+static int cycle_time = 120;
+
+/* Cirrus options */
+static int has_dma = -1;
+static int has_led = -1;
+static int has_ring = -1;
+static int dynamic_mode = 0;
+static int freq_bypass = -1;
+static int setup_time = -1;
+static int cmd_time = -1;
+static int recov_time = -1;
+
+#ifdef CONFIG_ISA
+/* Vadem options */
+static int async_clock = -1;
+static int cable_mode = -1;
+static int wakeup = 0;
+#endif
+
+#ifdef CONFIG_ISA
+MODULE_PARM(i365_base, "i");
+MODULE_PARM(ignore, "i");
+MODULE_PARM(extra_sockets, "i");
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-16i");
+MODULE_PARM(cs_irq, "i");
+MODULE_PARM(async_clock, "i");
+MODULE_PARM(cable_mode, "i");
+MODULE_PARM(wakeup, "i");
+#endif
+
+MODULE_PARM(do_scan, "i");
+MODULE_PARM(poll_interval, "i");
+MODULE_PARM(cycle_time, "i");
+MODULE_PARM(has_dma, "i");
+MODULE_PARM(has_led, "i");
+MODULE_PARM(has_ring, "i");
+MODULE_PARM(dynamic_mode, "i");
+MODULE_PARM(freq_bypass, "i");
+MODULE_PARM(setup_time, "i");
+MODULE_PARM(cmd_time, "i");
+MODULE_PARM(recov_time, "i");
+
+#ifdef CONFIG_PCI
+/* Scan PCI bus? */
+static int do_pci_probe = 1;
+/* Default memory base address for CardBus controllers */
+static u_int cb_mem_base[] = { 0x68000000, 0xf8000000 };
+static int fast_pci = -1;
+static int hold_time = -1;
+/* Override BIOS interrupt routing mode? */
+static int irq_mode = -1;
+static int has_clkrun = -1;
+static int clkrun_sel = -1;
+static int pci_latency = -1;
+static int cb_latency = -1;
+static int cb_bus_base = 0;
+static int cb_bus_step = 2;
+static int cb_write_post = -1;
+MODULE_PARM(do_pci_probe, "i");
+MODULE_PARM(cb_mem_base, "i");
+MODULE_PARM(fast_pci, "i");
+MODULE_PARM(hold_time, "i");
+MODULE_PARM(irq_mode, "i");
+MODULE_PARM(has_clkrun, "i");
+MODULE_PARM(clkrun_sel, "i");
+MODULE_PARM(pci_latency, "i");
+MODULE_PARM(cb_latency, "i");
+MODULE_PARM(cb_bus_base, "i");
+MODULE_PARM(cb_bus_step, "i");
+MODULE_PARM(cb_write_post, "i");
+#endif
+
+#ifdef CONFIG_ISA
+#ifdef CONFIG_PCI
+/* PCI card status change interrupts? */
+static int pci_csc = 0;
+/* PCI IO card functional interrupts? */
+static int pci_int = 0;
+MODULE_PARM(pci_csc, "i");
+MODULE_PARM(pci_int, "i");
+#else /* no PCI */
+#define pci_csc                0
+#define pci_int                0
+#endif
+#else /* no ISA */
+#ifdef CONFIG_PCI
+#define pci_csc                0
+#define pci_int                1
+#else
+#error "No bus architectures defined!"
+#endif
+#endif
+
+/*====================================================================*/
+
+typedef struct cirrus_state_t {
+    u_char             misc1, misc2;
+    u_char             timer[6];
+} cirrus_state_t;
+
+typedef struct vg46x_state_t {
+    u_char             ctl, ema;
+} vg46x_state_t;
+
+typedef struct ti113x_state_t {
+    u_int              sysctl;
+    u_char             cardctl, devctl, diag;
+} ti113x_state_t;
+
+typedef struct rl5c4xx_state_t {
+    u_short            misc, ctl, io, mem;
+} rl5c4xx_state_t;
+
+typedef struct o2micro_state_t {
+    u_char             mode_a, mode_b, mode_c, mode_d;
+    u_char             mhpg, fifo, mode_e;
+} o2micro_state_t;
+
+typedef struct topic_state_t {
+    u_char             slot, ccr, cdr;
+    u_int              rcr;
+} topic_state_t;
+
+typedef struct socket_info_t {
+    u_short            type, flags;
+    socket_cap_t       cap;
+    u_short            ioaddr;
+    u_short            psock;
+    u_char             cs_irq, intr;
+    void               (*handler)(void *info, u_int events);
+    void               *info;
+#ifdef CONFIG_PROC_FS
+    struct proc_dir_entry *proc;
+#endif
+#ifdef CONFIG_PCI
+    u_short            vendor, device;
+    u_char             revision, bus, devfn;
+    u_short            bcr;
+    u_char             pci_lat, cb_lat, sub_bus;
+    u_char             cache, pmcs;
+    u_int              cb_phys;
+    char               *cb_virt;
+#endif
+    union {
+       cirrus_state_t          cirrus;
+       vg46x_state_t           vg46x;
+#ifdef CONFIG_PCI
+       o2micro_state_t         o2micro;
+       ti113x_state_t          ti113x;
+       rl5c4xx_state_t         rl5c4xx;
+       topic_state_t           topic;
+#endif
+    } state;
+} socket_info_t;
+
+/* Where we keep track of our sockets... */
+static int sockets = 0;
+static socket_info_t socket[8] = {
+    { 0, }, /* ... */
+};
+
+/* Default ISA interrupt mask */
+#define I365_MASK      0xdeb8  /* irq 15,14,12,11,10,9,7,5,4,3 */
+
+static void pcic_interrupt_wrapper(u_long);
+static void pcic_interrupt(int irq, void *dev,
+                                   struct pt_regs *regs);
+static int pcic_service(u_int sock, u_int cmd, void *arg);
+#ifdef CONFIG_PROC_FS
+static void pcic_proc_remove(u_short sock);
+#endif
+
+#ifdef CONFIG_ISA
+static int grab_irq;
+static spinlock_t isa_lock = SPIN_LOCK_UNLOCKED;
+#endif
+static struct timer_list poll_timer;
+
+/*====================================================================*/
+
+#ifdef CONFIG_PCI
+
+#ifndef PCI_VENDOR_ID_INTEL
+#define PCI_VENDOR_ID_INTEL            0x8086
+#endif
+#ifndef PCI_VENDOR_ID_OMEGA
+#define PCI_VENDOR_ID_OMEGA            0x119b
+#endif
+#ifndef PCI_DEVICE_ID_OMEGA_PCMCIA
+#define PCI_DEVICE_ID_OMEGA_PCMCIA     0x1221
+#endif
+
+/* Default settings for PCI command configuration register */
+#define CMD_DFLT (PCI_COMMAND_IO|PCI_COMMAND_MEMORY| \
+                 PCI_COMMAND_MASTER|PCI_COMMAND_WAIT)
+
+#endif
+
+/* These definitions must match the pcic table! */
+typedef enum pcic_id {
+#ifdef CONFIG_ISA
+    IS_I82365A, IS_I82365B, IS_I82365DF,
+    IS_IBM, IS_RF5Cx96, IS_VLSI, IS_VG468, IS_VG469,
+    IS_PD6710, IS_PD672X, IS_VT83C469,
+#endif
+#ifdef CONFIG_PCI
+    IS_PD6729, IS_PD6730, IS_OZ6729, IS_OZ6730,
+    IS_I82092AA, IS_OM82C092G,
+    IS_PD6832, IS_OZ6832, IS_OZ6836,
+    IS_RL5C465, IS_RL5C466, IS_RL5C475, IS_RL5C476, IS_RL5C478,
+    IS_SMC34C90,
+    IS_TI1130, IS_TI1131, IS_TI1250A, IS_TI1220, IS_TI1221, IS_TI1210,
+    IS_TI1251A, IS_TI1251B, IS_TI1450, IS_TI1225,
+    IS_TOPIC95_A, IS_TOPIC95_B, IS_TOPIC97,
+    IS_UNK_PCI, IS_UNK_CARDBUS
+#endif
+} pcic_id;
+
+/* Flags for classifying groups of controllers */
+#define IS_VADEM       0x0001
+#define IS_CIRRUS      0x0002
+#define IS_TI          0x0004
+#define IS_O2MICRO     0x0008
+#define IS_VIA         0x0010
+#define IS_TOPIC       0x0020
+#define IS_RICOH       0x0040
+#define IS_UNKNOWN     0x0400
+#define IS_VG_PWR      0x0800
+#define IS_DF_PWR      0x1000
+#define IS_PCI         0x2000
+#define IS_CARDBUS     0x4000
+#define IS_ALIVE       0x8000
+
+typedef struct pcic_t {
+    char               *name;
+    u_short            flags;
+#ifdef CONFIG_PCI
+    u_short            vendor, device;
+#endif
+} pcic_t;
+
+static pcic_t pcic[] = {
+#ifdef CONFIG_ISA
+    { "Intel i82365sl A step", 0 },
+    { "Intel i82365sl B step", 0 },
+    { "Intel i82365sl DF", IS_DF_PWR },
+    { "IBM Clone", 0 },
+    { "Ricoh RF5C296/396", 0 },
+    { "VLSI 82C146", 0 },
+    { "Vadem VG-468", IS_VADEM },
+    { "Vadem VG-469", IS_VADEM|IS_VG_PWR },
+    { "Cirrus PD6710", IS_CIRRUS },
+    { "Cirrus PD672x", IS_CIRRUS },
+    { "VIA VT83C469", IS_CIRRUS|IS_VIA },
+#endif
+#ifdef CONFIG_PCI
+    { "Cirrus PD6729", IS_CIRRUS|IS_PCI,
+      PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_6729 },
+    { "Cirrus PD6730", IS_CIRRUS|IS_PCI,
+      PCI_VENDOR_ID_CIRRUS, 0xffff },
+    { "O2Micro OZ6729", IS_O2MICRO|IS_PCI|IS_VG_PWR,
+      PCI_VENDOR_ID_O2, PCI_DEVICE_ID_O2_6729 },
+    { "O2Micro OZ6730", IS_O2MICRO|IS_PCI|IS_VG_PWR,
+      PCI_VENDOR_ID_O2, PCI_DEVICE_ID_O2_6730 },
+    { "Intel 82092AA", IS_PCI,
+      PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_OMEGA_PCMCIA },
+    { "Omega Micro 82C092G", IS_PCI,
+      PCI_VENDOR_ID_OMEGA, PCI_DEVICE_ID_OMEGA_PCMCIA },
+    { "Cirrus PD6832", IS_CIRRUS|IS_CARDBUS,
+      PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_6832 },
+    { "O2Micro OZ6832/OZ6833", IS_O2MICRO|IS_CARDBUS|IS_VG_PWR,
+      PCI_VENDOR_ID_O2, PCI_DEVICE_ID_O2_6832 },
+    { "O2Micro OZ6836/OZ6860", IS_O2MICRO|IS_CARDBUS|IS_VG_PWR,
+      PCI_VENDOR_ID_O2, PCI_DEVICE_ID_O2_6836 },
+    { "Ricoh RL5C465", IS_RICOH|IS_CARDBUS|IS_DF_PWR,
+      PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C465 },
+    { "Ricoh RL5C466", IS_RICOH|IS_CARDBUS|IS_DF_PWR,
+      PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C466 },
+    { "Ricoh RL5C475", IS_RICOH|IS_CARDBUS|IS_DF_PWR,
+      PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C475 },
+    { "Ricoh RL5C476", IS_RICOH|IS_CARDBUS|IS_DF_PWR,
+      PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C476 },
+    { "Ricoh RL5C478", IS_RICOH|IS_CARDBUS|IS_DF_PWR,
+      PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C478 },
+    { "SMC 34C90", IS_CARDBUS|IS_DF_PWR,
+      PCI_VENDOR_ID_SMC, PCI_DEVICE_ID_SMC_34C90 },
+    { "TI 1130", IS_TI|IS_CARDBUS|IS_DF_PWR,
+      PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1130 },
+    { "TI 1131", IS_TI|IS_CARDBUS|IS_DF_PWR,
+      PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1131 },
+    { "TI 1250A", IS_TI|IS_CARDBUS|IS_DF_PWR,
+      PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1250A },
+    { "TI 1220", IS_TI|IS_CARDBUS|IS_DF_PWR,
+      PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1220 },
+    { "TI 1221", IS_TI|IS_CARDBUS|IS_DF_PWR,
+      PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1221 },
+    { "TI 1210", IS_TI|IS_CARDBUS|IS_DF_PWR,
+      PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1210 },
+    { "TI 1251A", IS_TI|IS_CARDBUS|IS_DF_PWR,
+      PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1251A },
+    { "TI 1251B", IS_TI|IS_CARDBUS|IS_DF_PWR,
+      PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1251B },
+    { "TI 1450", IS_TI|IS_CARDBUS|IS_DF_PWR,
+      PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1450 },
+    { "TI 1225", IS_TI|IS_CARDBUS|IS_DF_PWR,
+      PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1225 },
+    { "Toshiba ToPIC95-A", IS_CARDBUS|IS_TOPIC|IS_DF_PWR,
+      PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC95_A },
+    { "Toshiba ToPIC95-B", IS_CARDBUS|IS_TOPIC|IS_DF_PWR,
+      PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC95_B },
+    { "Toshiba ToPIC97", IS_CARDBUS|IS_TOPIC|IS_DF_PWR,
+      PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC97 },
+    { "Unknown", IS_PCI|IS_UNKNOWN, 0, 0 },
+    { "Unknown", IS_CARDBUS|IS_DF_PWR|IS_UNKNOWN, 0, 0 }
+#endif
+};
+
+#define PCIC_COUNT     (sizeof(pcic)/sizeof(pcic_t))
+
+/*====================================================================*/
+
+/* Some PCI shortcuts */
+
+#ifdef CONFIG_PCI
+
+#define pci_readb              pcibios_read_config_byte
+#define pci_writeb             pcibios_write_config_byte
+#define pci_readw              pcibios_read_config_word
+#define pci_writew             pcibios_write_config_word
+#define pci_readl              pcibios_read_config_dword
+#define pci_writel             pcibios_write_config_dword
+
+#define cb_readb(s, r)         readb(socket[s].cb_virt + (r))
+#define cb_readl(s, r)         readl(socket[s].cb_virt + (r))
+#define cb_writeb(s, r, v)     writeb(v, socket[s].cb_virt + (r))
+#define cb_writel(s, r, v)     writel(v, socket[s].cb_virt + (r))
+
+static void cb_get_power(u_short sock, socket_state_t *state);
+static void cb_set_power(u_short sock, socket_state_t *state);
+#endif
+
+/*====================================================================*/
+
+static u_char i365_get(u_short sock, u_short reg)
+{
+#ifdef CONFIG_PCI
+    if (socket[sock].cb_virt)
+       return cb_readb(sock, 0x0800 + reg);
+    else
+#endif
+    {
+       u_short port = socket[sock].ioaddr;
+       u_char val;
+       reg = I365_REG(socket[sock].psock, reg);
+       outb(reg, port); val = inb(port+1);
+       return val;
+    }
+}
+
+static void i365_set(u_short sock, u_short reg, u_char data)
+{
+#ifdef CONFIG_PCI
+    if (socket[sock].cb_virt)
+       cb_writeb(sock, 0x0800 + reg, data);
+    else
+#endif
+    {
+       u_short port = socket[sock].ioaddr;
+       u_char val = I365_REG(socket[sock].psock, reg);
+       outb(val, port); outb(data, port+1);
+    }
+}
+
+static void i365_bset(u_short sock, u_short reg, u_char mask)
+{
+    u_char d = i365_get(sock, reg);
+    d |= mask;
+    i365_set(sock, reg, d);
+}
+
+static void i365_bclr(u_short sock, u_short reg, u_char mask)
+{
+    u_char d = i365_get(sock, reg);
+    d &= ~mask;
+    i365_set(sock, reg, d);
+}
+
+static void i365_bflip(u_short sock, u_short reg, u_char mask, int b)
+{
+    u_char d = i365_get(sock, reg);
+    if (b)
+       d |= mask;
+    else
+       d &= ~mask;
+    i365_set(sock, reg, d);
+}
+
+static u_short i365_get_pair(u_short sock, u_short reg)
+{
+    u_short a, b;
+    a = i365_get(sock, reg);
+    b = i365_get(sock, reg+1);
+    return (a + (b<<8));
+}
+
+static void i365_set_pair(u_short sock, u_short reg, u_short data)
+{
+    i365_set(sock, reg, data & 0xff);
+    i365_set(sock, reg+1, data >> 8);
+}
+
+/*======================================================================
+
+    Code to save and restore global state information for Cirrus
+    PD67xx controllers, and to set and report global configuration
+    options.
+
+    The VIA controllers also use these routines, as they are mostly
+    Cirrus lookalikes, without the timing registers.
+    
+======================================================================*/
+
+#define flip(v,b,f) (v = ((f)<0) ? v : ((f) ? ((v)|(b)) : ((v)&(~b))))
+
+static void cirrus_get_state(u_short s)
+{
+    int i;
+    cirrus_state_t *p = &socket[s].state.cirrus;
+    p->misc1 = i365_get(s, PD67_MISC_CTL_1);
+    p->misc1 &= (PD67_MC1_MEDIA_ENA | PD67_MC1_INPACK_ENA);
+    p->misc2 = i365_get(s, PD67_MISC_CTL_2);
+    for (i = 0; i < 6; i++)
+       p->timer[i] = i365_get(s, PD67_TIME_SETUP(0)+i);
+}
+
+static void cirrus_set_state(u_short s)
+{
+    int i;
+    u_char misc;
+    cirrus_state_t *p = &socket[s].state.cirrus;
+
+    misc = i365_get(s, PD67_MISC_CTL_2);
+    i365_set(s, PD67_MISC_CTL_2, p->misc2);
+    if (misc & PD67_MC2_SUSPEND) mdelay(50);
+    misc = i365_get(s, PD67_MISC_CTL_1);
+    misc &= ~(PD67_MC1_MEDIA_ENA | PD67_MC1_INPACK_ENA);
+    i365_set(s, PD67_MISC_CTL_1, misc | p->misc1);
+    for (i = 0; i < 6; i++)
+       i365_set(s, PD67_TIME_SETUP(0)+i, p->timer[i]);
+}
+
+#ifdef CONFIG_PCI
+static int cirrus_set_irq_mode(u_short s, int pcsc, int pint)
+{
+    flip(socket[s].bcr, PD6832_BCR_MGMT_IRQ_ENA, !pcsc);
+    return 0;
+}
+#endif /* CONFIG_PCI */
+
+static u_int cirrus_set_opts(u_short s, char *buf)
+{
+    socket_info_t *t = &socket[s];
+    cirrus_state_t *p = &socket[s].state.cirrus;
+    u_int mask = 0xffff;
+
+    if (has_ring == -1) has_ring = 1;
+    flip(p->misc2, PD67_MC2_IRQ15_RI, has_ring);
+    flip(p->misc2, PD67_MC2_DYNAMIC_MODE, dynamic_mode);
+    if (p->misc2 & PD67_MC2_IRQ15_RI)
+       strcat(buf, " [ring]");
+    if (p->misc2 & PD67_MC2_DYNAMIC_MODE)
+       strcat(buf, " [dyn mode]");
+    if (p->misc1 & PD67_MC1_INPACK_ENA)
+       strcat(buf, " [inpack]");
+    if (!(t->flags & (IS_PCI | IS_CARDBUS))) {
+       if (p->misc2 & PD67_MC2_IRQ15_RI)
+           mask &= ~0x8000;
+       if (has_led > 0) {
+           strcat(buf, " [led]");
+           mask &= ~0x1000;
+       }
+       if (has_dma > 0) {
+           strcat(buf, " [dma]");
+           mask &= ~0x0600;
+       flip(p->misc2, PD67_MC2_FREQ_BYPASS, freq_bypass);
+       if (p->misc2 & PD67_MC2_FREQ_BYPASS)
+           strcat(buf, " [freq bypass]");
+       }
+#ifdef CONFIG_PCI
+    } else {
+       p->misc1 &= ~PD67_MC1_MEDIA_ENA;
+       flip(p->misc2, PD67_MC2_FAST_PCI, fast_pci);
+       if (p->misc2 & PD67_MC2_IRQ15_RI)
+           mask &= (socket[s].type == IS_PD6730) ? ~0x0400 : ~0x8000;
+#endif
+    }
+    if (!(t->flags & IS_VIA)) {
+       if (setup_time >= 0)
+           p->timer[0] = p->timer[3] = setup_time;
+       if (cmd_time > 0) {
+           p->timer[1] = cmd_time;
+           p->timer[4] = cmd_time*2+4;
+       }
+       if (p->timer[1] == 0) {
+           p->timer[1] = 6; p->timer[4] = 16;
+           if (p->timer[0] == 0)
+               p->timer[0] = p->timer[3] = 1;
+       }
+       if (recov_time >= 0)
+           p->timer[2] = p->timer[5] = recov_time;
+       buf += strlen(buf);
+       sprintf(buf, " [%d/%d/%d] [%d/%d/%d]", p->timer[0], p->timer[1],
+               p->timer[2], p->timer[3], p->timer[4], p->timer[5]);
+    }
+    return mask;
+}
+
+/*======================================================================
+
+    Code to save and restore global state information for Vadem VG468
+    and VG469 controllers, and to set and report global configuration
+    options.
+    
+======================================================================*/
+
+#ifdef CONFIG_ISA
+
+static void vg46x_get_state(u_short s)
+{
+    vg46x_state_t *p = &socket[s].state.vg46x;
+    p->ctl = i365_get(s, VG468_CTL);
+    if (socket[s].type == IS_VG469)
+       p->ema = i365_get(s, VG469_EXT_MODE);
+}
+
+static void vg46x_set_state(u_short s)
+{
+    vg46x_state_t *p = &socket[s].state.vg46x;
+    i365_set(s, VG468_CTL, p->ctl);
+    if (socket[s].type == IS_VG469)
+       i365_set(s, VG469_EXT_MODE, p->ema);
+}
+
+static u_int vg46x_set_opts(u_short s, char *buf)
+{
+    vg46x_state_t *p = &socket[s].state.vg46x;
+    
+    flip(p->ctl, VG468_CTL_ASYNC, async_clock);
+    flip(p->ema, VG469_MODE_CABLE, cable_mode);
+    if (p->ctl & VG468_CTL_ASYNC)
+       strcat(buf, " [async]");
+    if (p->ctl & VG468_CTL_INPACK)
+       strcat(buf, " [inpack]");
+    if (socket[s].type == IS_VG469) {
+       u_char vsel = i365_get(s, VG469_VSELECT);
+       if (vsel & VG469_VSEL_EXT_STAT) {
+           strcat(buf, " [ext mode]");
+           if (vsel & VG469_VSEL_EXT_BUS)
+               strcat(buf, " [isa buf]");
+       }
+       if (p->ema & VG469_MODE_CABLE)
+           strcat(buf, " [cable]");
+       if (p->ema & VG469_MODE_COMPAT)
+           strcat(buf, " [c step]");
+    }
+    return 0xffff;
+}
+
+#endif
+
+/*======================================================================
+
+    Code to save and restore global state information for TI 1130 and
+    TI 1131 controllers, and to set and report global configuration
+    options.
+    
+======================================================================*/
+
+#ifdef CONFIG_PCI
+
+static void ti113x_get_state(u_short s)
+{
+    socket_info_t *t = &socket[s];
+    ti113x_state_t *p = &socket[s].state.ti113x;
+    pci_readl(t->bus, t->devfn, TI113X_SYSTEM_CONTROL, &p->sysctl);
+    pci_readb(t->bus, t->devfn, TI113X_CARD_CONTROL, &p->cardctl);
+    pci_readb(t->bus, t->devfn, TI113X_DEVICE_CONTROL, &p->devctl);
+    pci_readb(t->bus, t->devfn, TI1250_DIAGNOSTIC, &p->diag);
+}
+
+static void ti113x_set_state(u_short s)
+{
+    socket_info_t *t = &socket[s];
+    ti113x_state_t *p = &socket[s].state.ti113x;
+    pci_writel(t->bus, t->devfn, TI113X_SYSTEM_CONTROL, p->sysctl);
+    pci_writeb(t->bus, t->devfn, TI113X_CARD_CONTROL, p->cardctl);
+    pci_writeb(t->bus, t->devfn, TI113X_DEVICE_CONTROL, p->devctl);
+    pci_writeb(t->bus, t->devfn, TI1250_MULTIMEDIA_CTL, 0);
+    pci_writeb(t->bus, t->devfn, TI1250_DIAGNOSTIC, p->diag);
+    i365_set_pair(s, TI113X_IO_OFFSET(0), 0);
+    i365_set_pair(s, TI113X_IO_OFFSET(1), 0);
+}
+
+static int ti113x_set_irq_mode(u_short s, int pcsc, int pint)
+{
+    socket_info_t *t = &socket[s];
+    ti113x_state_t *p = &t->state.ti113x;
+    t->intr = (pcsc) ? I365_INTR_ENA : 0;
+    if (t->type <= IS_TI1131) {
+       p->cardctl &= ~(TI113X_CCR_PCI_IRQ_ENA |
+                       TI113X_CCR_PCI_IREQ | TI113X_CCR_PCI_CSC);
+       if (pcsc)
+           p->cardctl |= TI113X_CCR_PCI_IRQ_ENA | TI113X_CCR_PCI_CSC;
+       if (pint)
+           p->cardctl |= TI113X_CCR_PCI_IRQ_ENA | TI113X_CCR_PCI_IREQ;
+    } else if (t->type == IS_TI1250A) {
+       p->diag &= TI1250_DIAG_PCI_CSC | TI1250_DIAG_PCI_IREQ;
+       if (pcsc)
+           p->diag |= TI1250_DIAG_PCI_CSC;
+       if (pint)
+           p->diag |= TI1250_DIAG_PCI_IREQ;
+    }
+    return 0;
+}
+
+static u_int ti113x_set_opts(u_short s, char *buf)
+{
+    socket_info_t *t = &socket[s];
+    ti113x_state_t *p = &t->state.ti113x;
+    u_int mask = 0xffff;
+    int old = (t->type <= IS_TI1131);
+    
+    flip(p->sysctl, TI113X_SCR_CLKRUN_ENA, has_clkrun);
+    flip(p->sysctl, TI113X_SCR_CLKRUN_SEL, clkrun_sel);
+    flip(p->cardctl, TI113X_CCR_RIENB, has_ring);
+    p->cardctl &= ~TI113X_CCR_ZVENABLE;
+    switch (irq_mode) {
+    case 1:
+       p->devctl &= ~TI113X_DCR_IMODE_MASK;
+       p->devctl |= TI113X_DCR_IMODE_ISA;
+       break;
+    case 2:
+       p->devctl &= ~TI113X_DCR_IMODE_MASK;
+       p->devctl |= TI113X_DCR_IMODE_SERIAL;
+       break;
+    case 3:
+       p->devctl &= ~TI113X_DCR_IMODE_MASK;
+       p->devctl |= TI12XX_DCR_IMODE_ALL_SERIAL;
+       break;
+    default:
+       if ((p->devctl & TI113X_DCR_IMODE_MASK) == 0)
+           p->devctl |= TI113X_DCR_IMODE_ISA;
+    }
+    if (p->cardctl & TI113X_CCR_RIENB) {
+       strcat(buf, " [ring]");
+       if (old) mask &= ~0x8000;
+    }
+    if (old && (p->sysctl & TI113X_SCR_CLKRUN_ENA)) {
+       if (p->sysctl & TI113X_SCR_CLKRUN_SEL) {
+           strcat(buf, " [clkrun irq 12]");
+           mask &= ~0x1000;
+       } else {
+           strcat(buf, " [clkrun irq 10]");
+           mask &= ~0x0400;
+       }
+    }
+    if (p->sysctl & TI113X_SCR_PWRSAVINGS)
+       strcat(buf, " [pwr save]");
+    switch (p->devctl & TI113X_DCR_IMODE_MASK) {
+    case TI12XX_DCR_IMODE_PCI_ONLY:
+       strcat(buf, " [pci only]");
+       mask = 0;
+       break;
+    case TI113X_DCR_IMODE_ISA:
+       strcat(buf, " [isa irq]");
+       if (old) mask &= ~0x0018;
+       break;
+    case TI113X_DCR_IMODE_SERIAL:
+       strcat(buf, " [pci + serial irq]");
+       mask = 0xffff;
+       break;
+    case TI12XX_DCR_IMODE_ALL_SERIAL:
+       strcat(buf, " [serial pci & irq]");
+       mask = 0xffff;
+       break;
+    }
+    return mask;
+}
+
+#endif
+
+/*======================================================================
+
+    Code to save and restore global state information for the Ricoh
+    RL5C4XX controllers, and to set and report global configuration
+    options.
+    
+======================================================================*/
+
+#ifdef CONFIG_PCI
+
+static void rl5c4xx_get_state(u_short s)
+{
+    socket_info_t *t = &socket[s];
+    rl5c4xx_state_t *p = &socket[s].state.rl5c4xx;
+    pci_readw(t->bus, t->devfn, RL5C4XX_MISC, &p->misc);
+    pci_readw(t->bus, t->devfn, RL5C4XX_16BIT_CTL, &p->ctl);
+    pci_readw(t->bus, t->devfn, RL5C4XX_16BIT_IO_0, &p->io);
+    pci_readw(t->bus, t->devfn, RL5C4XX_16BIT_MEM_0, &p->mem);
+}
+
+static void rl5c4xx_set_state(u_short s)
+{
+    socket_info_t *t = &socket[s];
+    rl5c4xx_state_t *p = &socket[s].state.rl5c4xx;
+    pci_writew(t->bus, t->devfn, RL5C4XX_MISC, p->misc);
+    pci_writew(t->bus, t->devfn, RL5C4XX_16BIT_CTL, p->ctl);
+    pci_writew(t->bus, t->devfn, RL5C4XX_16BIT_IO_0, p->io);
+    pci_writew(t->bus, t->devfn, RL5C4XX_16BIT_MEM_0, p->mem);
+}
+
+static u_int rl5c4xx_set_opts(u_short s, char *buf)
+{
+    rl5c4xx_state_t *p = &socket[s].state.rl5c4xx;
+    u_int mask = 0xffff;
+    int old = (socket[s].type < IS_RL5C475);
+
+    p->ctl = RL5C4XX_16CTL_IO_TIMING | RL5C4XX_16CTL_MEM_TIMING;
+    if (old) p->ctl |= RL5C46X_16CTL_LEVEL_1 | RL5C46X_16CTL_LEVEL_2;
+    
+    if (setup_time >= 0) {
+       p->io = (p->io & ~RL5C4XX_SETUP_MASK) +
+           ((setup_time+1) << RL5C4XX_SETUP_SHIFT);
+       p->mem = (p->mem & ~RL5C4XX_SETUP_MASK) +
+           (setup_time << RL5C4XX_SETUP_SHIFT);
+    }
+    if (cmd_time >= 0) {
+       p->io = (p->io & ~RL5C4XX_CMD_MASK) +
+           (cmd_time << RL5C4XX_CMD_SHIFT);
+       p->mem = (p->mem & ~RL5C4XX_CMD_MASK) +
+           (cmd_time << RL5C4XX_CMD_SHIFT);
+    }
+    if (hold_time >= 0) {
+       p->io = (p->io & ~RL5C4XX_HOLD_MASK) +
+           (hold_time << RL5C4XX_HOLD_SHIFT);
+       p->mem = (p->mem & ~RL5C4XX_HOLD_MASK) +
+           (hold_time << RL5C4XX_HOLD_SHIFT);
+    }
+    if (!old) {
+       switch (irq_mode) {
+       case 1:
+           p->misc &= ~RL5C47X_MISC_SRIRQ_ENA; break;
+       case 2:
+           p->misc |= RL5C47X_MISC_SRIRQ_ENA; break;
+       }
+       if (p->misc & RL5C47X_MISC_SRIRQ_ENA)
+           sprintf(buf, " [serial irq]");
+       else
+           sprintf(buf, " [isa irq]");
+       buf += strlen(buf);
+    }
+    sprintf(buf, " [io %d/%d/%d] [mem %d/%d/%d]",
+           (p->io & RL5C4XX_SETUP_MASK) >> RL5C4XX_SETUP_SHIFT,
+           (p->io & RL5C4XX_CMD_MASK) >> RL5C4XX_CMD_SHIFT,
+           (p->io & RL5C4XX_HOLD_MASK) >> RL5C4XX_HOLD_SHIFT,
+           (p->mem & RL5C4XX_SETUP_MASK) >> RL5C4XX_SETUP_SHIFT,
+           (p->mem & RL5C4XX_CMD_MASK) >> RL5C4XX_CMD_SHIFT,
+           (p->mem & RL5C4XX_HOLD_MASK) >> RL5C4XX_HOLD_SHIFT);
+    return mask;
+}
+
+#endif
+
+/*======================================================================
+
+    Code to save and restore global state information for O2Micro
+    controllers, and to set and report global configuration options.
+    
+======================================================================*/
+
+#ifdef CONFIG_PCI
+
+static void o2micro_get_state(u_short s)
+{
+    socket_info_t *t = &socket[s];
+    o2micro_state_t *p = &socket[s].state.o2micro;
+    if ((t->revision == 0x34) || (t->revision == 0x62)) {
+       p->mode_a = i365_get(s, O2_MODE_A_2);
+       p->mode_b = i365_get(s, O2_MODE_B_2);
+    } else {
+       p->mode_a = i365_get(s, O2_MODE_A);
+       p->mode_b = i365_get(s, O2_MODE_B);
+    }
+    p->mode_c = i365_get(s, O2_MODE_C);
+    p->mode_d = i365_get(s, O2_MODE_D);
+    if (t->flags & IS_CARDBUS) {
+       p->mhpg = i365_get(s, O2_MHPG_DMA);
+       p->fifo = i365_get(s, O2_FIFO_ENA);
+       p->mode_e = i365_get(s, O2_MODE_E);
+    }
+}
+
+static void o2micro_set_state(u_short s)
+{
+    socket_info_t *t = &socket[s];
+    o2micro_state_t *p = &socket[s].state.o2micro;
+    if ((t->revision == 0x34) || (t->revision == 0x62)) {
+       i365_set(s, O2_MODE_A_2, p->mode_a);
+       i365_set(s, O2_MODE_B_2, p->mode_b);
+    } else {
+       i365_set(s, O2_MODE_A, p->mode_a);
+       i365_set(s, O2_MODE_B, p->mode_b);
+    }
+    i365_set(s, O2_MODE_C, p->mode_c);
+    i365_set(s, O2_MODE_D, p->mode_d);
+    if (t->flags & IS_CARDBUS) {
+       i365_set(s, O2_MHPG_DMA, p->mhpg);
+       i365_set(s, O2_FIFO_ENA, p->fifo);
+       i365_set(s, O2_MODE_E, p->mode_e);
+    }
+}
+
+static u_int o2micro_set_opts(u_short s, char *buf)
+{
+    socket_info_t *t = &socket[s];
+    o2micro_state_t *p = &socket[s].state.o2micro;
+    u_int mask = 0xffff;
+
+    p->mode_b = (p->mode_b & ~O2_MODE_B_IDENT) | O2_MODE_B_ID_CSTEP;
+    flip(p->mode_b, O2_MODE_B_IRQ15_RI, has_ring);
+    p->mode_c &= ~(O2_MODE_C_ZVIDEO | O2_MODE_C_DREQ_MASK);
+    if (t->flags & IS_CARDBUS) {
+       p->mode_d &= ~O2_MODE_D_W97_IRQ;
+       p->mode_e &= ~O2_MODE_E_MHPG_DMA;
+       p->mhpg |= O2_MHPG_CINT_ENA | O2_MHPG_CSC_ENA;
+       p->mhpg &= ~O2_MHPG_CHANNEL;
+    } else {
+       if (p->mode_b & O2_MODE_B_IRQ15_RI) mask &= ~0x8000;
+    }
+    sprintf(buf, " [a %02x] [b %02x] [c %02x] [d %02x]",
+           p->mode_a, p->mode_b, p->mode_c, p->mode_d);
+    if (t->flags & IS_CARDBUS) {
+       buf += strlen(buf);
+       sprintf(buf, " [mhpg %02x] [fifo %02x] [e %02x]",
+               p->mhpg, p->fifo, p->mode_e);
+    }
+    return mask;
+}
+
+#endif
+
+/*======================================================================
+
+    Code to save and restore global state information for the Toshiba
+    ToPIC 95 and 97 controllers, and to set and report global
+    configuration options.
+    
+======================================================================*/
+
+#ifdef CONFIG_PCI
+
+static void topic_get_state(u_short s)
+{
+    socket_info_t *t = &socket[s];
+    topic_state_t *p = &socket[s].state.topic;
+    pci_readb(t->bus, t->devfn, TOPIC_SLOT_CONTROL, &p->slot);
+    pci_readb(t->bus, t->devfn, TOPIC_CARD_CONTROL, &p->ccr);
+    pci_readb(t->bus, t->devfn, TOPIC_CARD_DETECT, &p->cdr);
+    pci_readl(t->bus, t->devfn, TOPIC_REGISTER_CONTROL, &p->rcr);
+}
+
+static void topic_set_state(u_short s)
+{
+    socket_info_t *t = &socket[s];
+    topic_state_t *p = &socket[s].state.topic;
+    pci_writeb(t->bus, t->devfn, TOPIC_SLOT_CONTROL, p->slot);
+    pci_writeb(t->bus, t->devfn, TOPIC_CARD_CONTROL, p->ccr);
+    pci_writeb(t->bus, t->devfn, TOPIC_CARD_DETECT, p->cdr);
+    pci_writel(t->bus, t->devfn, TOPIC_REGISTER_CONTROL, p->rcr);
+}
+
+static int topic_set_irq_mode(u_short s, int pcsc, int pint)
+{
+    if (socket[s].type == IS_TOPIC97) {
+       topic_state_t *p = &socket[s].state.topic;
+       flip(p->ccr, TOPIC97_ICR_IRQSEL, pcsc);
+       return 0;
+    } else {
+       return !pcsc;
+    }
+}
+
+static u_int topic_set_opts(u_short s, char *buf)
+{
+    topic_state_t *p = &socket[s].state.topic;
+
+    p->slot |= TOPIC_SLOT_SLOTON|TOPIC_SLOT_SLOTEN|TOPIC_SLOT_ID_LOCK;
+    p->cdr |= TOPIC_CDR_MODE_PC32;
+    p->cdr &= ~(TOPIC_CDR_SW_DETECT);
+    sprintf(buf, " [slot 0x%02x] [ccr 0x%02x] [cdr 0x%02x] [rcr 0x%02x]",
+           p->slot, p->ccr, p->cdr, p->rcr);
+    return 0xffff;
+}
+
+#endif
+
+/*======================================================================
+
+    Routines to handle common CardBus options
+    
+======================================================================*/
+
+#ifdef CONFIG_PCI
+
+static void cb_get_state(u_short s)
+{
+    socket_info_t *t = &socket[s];
+    
+    pci_readb(t->bus, t->devfn, PCI_CACHE_LINE_SIZE, &t->cache);
+    pci_readb(t->bus, t->devfn, PCI_LATENCY_TIMER, &t->pci_lat);
+    pci_readb(t->bus, t->devfn, CB_LATENCY_TIMER, &t->cb_lat);
+    pci_readb(t->bus, t->devfn, CB_CARDBUS_BUS, &t->cap.cardbus);
+    pci_readb(t->bus, t->devfn, CB_SUBORD_BUS, &t->sub_bus);
+    pci_readw(t->bus, t->devfn, CB_BRIDGE_CONTROL, &t->bcr);
+    {
+       struct pci_dev *pdev = pci_find_slot(t->bus, t->devfn);
+       t->cap.pci_irq = (pdev) ? pdev->irq : 0;
+    }
+    if (t->cap.pci_irq >= NR_IRQS) t->cap.pci_irq = 0;
+}
+
+static void cb_set_state(u_short s)
+{
+    socket_info_t *t = &socket[s];
+    if (t->pmcs)
+       pci_writew(t->bus, t->devfn, t->pmcs, PCI_PMCS_PWR_STATE_D0);
+    pci_writel(t->bus, t->devfn, CB_LEGACY_MODE_BASE, 0);
+    pci_writel(t->bus, t->devfn, PCI_BASE_ADDRESS_0, t->cb_phys);
+    pci_writew(t->bus, t->devfn, PCI_COMMAND, CMD_DFLT);
+    pci_writeb(t->bus, t->devfn, PCI_CACHE_LINE_SIZE, t->cache);
+    pci_writeb(t->bus, t->devfn, PCI_LATENCY_TIMER, t->pci_lat);
+    pci_writeb(t->bus, t->devfn, CB_LATENCY_TIMER, t->cb_lat);
+    pci_writeb(t->bus, t->devfn, CB_CARDBUS_BUS, t->cap.cardbus);
+    pci_writeb(t->bus, t->devfn, CB_SUBORD_BUS, t->sub_bus);
+    pci_writew(t->bus, t->devfn, CB_BRIDGE_CONTROL, t->bcr);
+}
+
+static int cb_get_irq_mode(u_short s)
+{
+    return (!(socket[s].bcr & CB_BCR_ISA_IRQ));
+}
+
+static int cb_set_irq_mode(u_short s, int pcsc, int pint)
+{
+    socket_info_t *t = &socket[s];
+    flip(t->bcr, CB_BCR_ISA_IRQ, !(pint));
+    if (t->flags & IS_CIRRUS)
+       return cirrus_set_irq_mode(s, pcsc, pint);
+    else if (t->flags & IS_TI)
+       return ti113x_set_irq_mode(s, pcsc, pint);
+    else if (t->flags & IS_TOPIC)
+       return topic_set_irq_mode(s, pcsc, pint);
+    return 0;
+}
+
+static void pci_scan(u_short sock);
+
+static void cb_set_opts(u_short s, char *buf)
+{
+    socket_info_t *t = &socket[s];
+    t->bcr |= CB_BCR_WRITE_POST;
+    /* some TI1130's seem to exhibit problems with write posting */
+    if (((t->type == IS_TI1130) && (t->revision == 4) &&
+        (cb_write_post < 0)) || (cb_write_post == 0))
+       t->bcr &= ~CB_BCR_WRITE_POST;
+    if (t->cache == 0) t->cache = 8;
+    if (pci_latency >= 0) t->pci_lat = pci_latency;
+    if (t->pci_lat == 0) t->pci_lat = 0xa8;
+    if (cb_latency >= 0) t->cb_lat = cb_latency;
+    if (t->cb_lat == 0) t->cb_lat = 0xb0;
+    if ((t->cap.pci_irq == 0) && (pci_csc || pci_int) && do_scan)
+       pci_scan(s);
+    if (t->cap.pci_irq == 0)
+       strcat(buf, " [no pci irq]");
+    else
+       sprintf(buf, " [pci irq %d]", t->cap.pci_irq);
+    buf += strlen(buf);
+    if ((cb_bus_base > 0) || (t->cap.cardbus == 0)) {
+       if (cb_bus_base <= 0) cb_bus_base = 0x20;
+       t->cap.cardbus = cb_bus_base;
+       t->sub_bus = cb_bus_base+cb_bus_step;
+       cb_bus_base += cb_bus_step+1;
+    }
+    if (!(t->flags & IS_TOPIC))
+       t->cap.features |= SS_CAP_PAGE_REGS;
+    sprintf(buf, " [lat %d/%d] [bus %d/%d]",
+           t->pci_lat, t->cb_lat, t->cap.cardbus, t->sub_bus);
+}
+
+#endif
+
+/*======================================================================
+
+    Generic routines to get and set controller options
+    
+======================================================================*/
+
+static void get_host_state(u_short s)
+{
+    socket_info_t *t = &socket[s];
+    if (t->flags & IS_CIRRUS)
+       cirrus_get_state(s);
+#ifdef CONFIG_ISA
+    else if (t->flags & IS_VADEM)
+       vg46x_get_state(s);
+#endif
+#ifdef CONFIG_PCI
+    else if (t->flags & IS_O2MICRO)
+       o2micro_get_state(s);
+    else if (t->flags & IS_TI)
+       ti113x_get_state(s);
+    else if (t->flags & IS_RICOH)
+       rl5c4xx_get_state(s);
+    else if (t->flags & IS_TOPIC)
+       topic_get_state(s);
+    if (t->flags & IS_CARDBUS)
+       cb_get_state(s);
+#endif
+}
+
+static void set_host_state(u_short s)
+{
+    socket_info_t *t = &socket[s];
+#ifdef CONFIG_PCI
+    if (t->flags & IS_CARDBUS)
+       cb_set_state(s);
+#endif
+    if (t->flags & IS_CIRRUS)
+       cirrus_set_state(s);
+    else {
+       i365_set(s, I365_GBLCTL, 0x00);
+       i365_set(s, I365_GENCTL, 0x00);
+    }
+    i365_bflip(s, I365_INTCTL, I365_INTR_ENA, t->intr);
+#ifdef CONFIG_ISA
+    if (t->flags & IS_VADEM)
+       vg46x_set_state(s);
+#endif
+#ifdef CONFIG_PCI
+    if (t->flags & IS_O2MICRO)
+       o2micro_set_state(s);
+    else if (t->flags & IS_TI)
+       ti113x_set_state(s);
+    else if (t->flags & IS_RICOH)
+       rl5c4xx_set_state(s);
+    else if (t->flags & IS_TOPIC)
+       topic_set_state(s);
+#endif
+}
+
+static u_int set_host_opts(u_short s, u_short ns)
+{
+    u_short i;
+    u_int m = 0xffff;
+    char buf[128];
+
+    for (i = s; i < s+ns; i++) {
+       if (socket[i].flags & IS_ALIVE) {
+           printk(KERN_INFO "    host opts [%d]: already alive!\n", i);
+           continue;
+       }
+       buf[0] = '\0';
+       get_host_state(i);
+       if (socket[i].flags & IS_CIRRUS)
+           m = cirrus_set_opts(i, buf);
+#ifdef CONFIG_ISA
+       else if (socket[i].flags & IS_VADEM)
+           m = vg46x_set_opts(i, buf);
+#endif
+#ifdef CONFIG_PCI
+       else if (socket[i].flags & IS_O2MICRO)
+           m = o2micro_set_opts(i, buf);
+       else if (socket[i].flags & IS_TI)
+           m = ti113x_set_opts(i, buf);
+       else if (socket[i].flags & IS_RICOH)
+           m = rl5c4xx_set_opts(i, buf);
+       else if (socket[i].flags & IS_TOPIC)
+           m = topic_set_opts(i, buf);
+       if (socket[i].flags & IS_CARDBUS)
+           cb_set_opts(i, buf+strlen(buf));
+#endif
+       set_host_state(i);
+       printk(KERN_INFO "    host opts [%d]:%s\n", i,
+              (*buf) ? buf : " none");
+    }
+#ifdef CONFIG_PCI
+    /* Mask out all PCI interrupts */
+    for (i = 0; i < sockets; i++)
+       m &= ~(1<<socket[i].cap.pci_irq);
+    {
+       struct pci_dev *p;
+       for (p = pci_devices; p; p = p->next)
+           m &= ~(1<<p->irq);
+    }
+#endif
+    return m;
+}
+
+/*======================================================================
+
+    Interrupt testing code, for ISA and PCI interrupts
+    
+======================================================================*/
+
+static volatile u_int irq_hits;
+static u_short irq_sock;
+
+static void irq_count(int irq, void *dev, struct pt_regs *regs)
+{
+#ifdef CONFIG_PCI
+    if (socket[irq_sock].flags & IS_CARDBUS) {
+       cb_writel(irq_sock, CB_SOCKET_EVENT, -1);
+    } else
+#endif
+    i365_get(irq_sock, I365_CSC);
+    irq_hits++;
+    DEBUG(2, ("-> hit on irq %d\n", irq));
+}
+
+static u_int test_irq(u_short sock, int irq, int pci)
+{
+    u_char csc = (pci) ? 0 : irq;
+    DEBUG(2, ("  testing %s irq %d\n", pci ? "PCI" : "ISA", irq));
+    
+    if (request_irq(irq, irq_count, (pci?SA_SHIRQ:0), "scan", NULL) != 0)
+       return 1;
+    irq_hits = 0; irq_sock = sock;
+    current->state = TASK_INTERRUPTIBLE;
+    schedule_timeout(HZ/100);
+    if (irq_hits) {
+       free_irq(irq, NULL);
+       DEBUG(2, ("    spurious hit!\n"));
+       return 1;
+    }
+
+    /* Generate one interrupt */
+#ifdef CONFIG_PCI
+    if (socket[sock].flags & IS_CARDBUS) {
+       cb_writel(sock, CB_SOCKET_EVENT, -1);
+       i365_set(sock, I365_CSCINT, I365_CSC_STSCHG | (csc << 4));
+       cb_writel(sock, CB_SOCKET_EVENT, -1);
+       cb_writel(sock, CB_SOCKET_MASK, CB_SM_CSTSCHG);
+       cb_writel(sock, CB_SOCKET_FORCE, CB_SE_CSTSCHG|0x410);
+       udelay(1000);
+       cb_writel(sock, CB_SOCKET_EVENT, -1);
+       cb_writel(sock, CB_SOCKET_MASK, 0);
+    } else
+#endif
+    {
+       i365_set(sock, I365_CSCINT, I365_CSC_DETECT | (csc << 4));
+       i365_bset(sock, I365_GENCTL, I365_CTL_SW_IRQ);
+       udelay(1000);
+    }
+
+    free_irq(irq, NULL);
+
+    /* mask all interrupts */
+    i365_set(sock, I365_CSCINT, 0);
+    DEBUG(2, ("    hits = %d\n", irq_hits));
+    
+    return (irq_hits != 1);
+}
+
+#ifdef CONFIG_ISA
+
+static u_int isa_scan(u_short sock, u_int mask0)
+{
+    u_int mask1 = 0;
+    int i;
+
+#ifdef __alpha__
+#define PIC 0x4d0
+    /* Don't probe level-triggered interrupts -- reserved for PCI */
+    mask0 &= ~(inb(PIC) | (inb(PIC+1) << 8));
+#endif
+    
+#ifdef CONFIG_PCI
+    /* Only scan if we can select ISA csc irq's */
+    if (!(socket[sock].flags & IS_CARDBUS) ||
+       (cb_set_irq_mode(sock, 0, 0) == 0))
+#endif
+       if (do_scan) {
+           set_host_state(sock);
+           i365_set(sock, I365_CSCINT, 0);
+           for (i = 0; i < 16; i++)
+               if ((mask0 & (1 << i)) && (test_irq(sock, i, 0) == 0))
+                   mask1 |= (1 << i);
+           for (i = 0; i < 16; i++)
+               if ((mask1 & (1 << i)) && (test_irq(sock, i, 0) != 0))
+                   mask1 ^= (1 << i);
+       }
+    
+    printk(KERN_INFO "    ISA irqs (");
+    if (mask1) {
+       printk("scanned");
+    } else {
+       /* Fallback: just find interrupts that aren't in use */
+       for (i = 0; i < 16; i++)
+           if ((mask0 & (1 << i)) && (_check_irq(i, 0) == 0))
+               mask1 |= (1 << i);
+       printk("default");
+       /* If scan failed, default to polled status */
+       if (!cs_irq && (poll_interval == 0)) poll_interval = HZ;
+    }
+    printk(") = ");
+    
+    for (i = 0; i < 16; i++)
+       if (mask1 & (1<<i))
+           printk("%s%d", ((mask1 & ((1<<i)-1)) ? "," : ""), i);
+    if (mask1 == 0) printk("none!");
+    
+    return mask1;
+}
+
+#endif /* CONFIG_ISA */
+
+#ifdef CONFIG_PCI
+
+static void pci_scan(u_short sock)
+{
+    u_int i;
+
+    cb_set_irq_mode(sock, 1, 0);
+    set_host_state(sock);
+    i365_set(sock, I365_CSCINT, 0);
+    /* Only probe irq's 9..11, to be conservative */
+    for (i = 9; i < 12; i++) {
+       if ((test_irq(sock, i, 1) == 0) &&
+           (test_irq(sock, i, 1) == 0))
+           break;
+    }
+    if (i < 12) socket[sock].cap.pci_irq = i;
+}
+
+#endif /* CONFIG_PCI */
+
+/*====================================================================*/
+
+/* Time conversion functions */
+
+static int to_cycles(int ns)
+{
+    return ns/cycle_time;
+} /* speed_convert */
+
+static int to_ns(int cycles)
+{
+    return cycle_time*cycles;
+}
+
+/*====================================================================*/
+
+#ifdef CONFIG_ISA
+
+static int identify(u_short port, u_short sock)
+{
+    u_char val;
+    int type = -1;
+
+    /* Use the next free entry in the socket table */
+    socket[sockets].ioaddr = port;
+    socket[sockets].psock = sock;
+    
+    /* Wake up a sleepy Cirrus controller */
+    if (wakeup) {
+       i365_bclr(sockets, PD67_MISC_CTL_2, PD67_MC2_SUSPEND);
+       /* Pause at least 50 ms */
+       mdelay(50);
+    }
+    
+    if ((val = i365_get(sockets, I365_IDENT)) & 0x70)
+       return -1;
+    switch (val) {
+    case 0x82:
+       type = IS_I82365A; break;
+    case 0x83:
+       type = IS_I82365B; break;
+    case 0x84:
+       type = IS_I82365DF; break;
+    case 0x88: case 0x89: case 0x8a:
+       type = IS_IBM; break;
+    }
+    
+    /* Check for Vadem VG-468 chips */
+    outb(0x0e, port);
+    outb(0x37, port);
+    i365_bset(sockets, VG468_MISC, VG468_MISC_VADEMREV);
+    val = i365_get(sockets, I365_IDENT);
+    if (val & I365_IDENT_VADEM) {
+       i365_bclr(sockets, VG468_MISC, VG468_MISC_VADEMREV);
+       type = ((val & 7) >= 4) ? IS_VG469 : IS_VG468;
+    }
+
+    /* Check for Ricoh chips */
+    val = i365_get(sockets, RF5C_CHIP_ID);
+    if ((val == RF5C_CHIP_RF5C296) || (val == RF5C_CHIP_RF5C396))
+       type = IS_RF5Cx96;
+    
+    /* Check for Cirrus CL-PD67xx chips */
+    i365_set(sockets, PD67_CHIP_INFO, 0);
+    val = i365_get(sockets, PD67_CHIP_INFO);
+    if ((val & PD67_INFO_CHIP_ID) == PD67_INFO_CHIP_ID) {
+       val = i365_get(sockets, PD67_CHIP_INFO);
+       if ((val & PD67_INFO_CHIP_ID) == 0) {
+           type = (val & PD67_INFO_SLOTS) ? IS_PD672X : IS_PD6710;
+           i365_set(sockets, PD67_EXT_INDEX, 0xe5);
+           if (i365_get(sockets, PD67_EXT_INDEX) != 0xe5)
+               type = IS_VT83C469;
+       }
+    }
+    return type;
+} /* identify */
+
+#endif
+
+/*======================================================================
+
+    See if a card is present, powered up, in IO mode, and already
+    bound to a (non PC Card) Linux driver.  We leave these alone.
+
+    We make an exception for cards that seem to be serial devices.
+    
+======================================================================*/
+
+static int is_alive(u_short sock)
+{
+    u_char stat;
+    u_short start, stop;
+    
+    stat = i365_get(sock, I365_STATUS);
+    start = i365_get_pair(sock, I365_IO(0)+I365_W_START);
+    stop = i365_get_pair(sock, I365_IO(0)+I365_W_STOP);
+    if ((stat & I365_CS_DETECT) && (stat & I365_CS_POWERON) &&
+       (i365_get(sock, I365_INTCTL) & I365_PC_IOCARD) &&
+       (i365_get(sock, I365_ADDRWIN) & I365_ENA_IO(0)) &&
+       (check_region(start, stop-start+1) != 0) &&
+       ((start & 0xfeef) != 0x02e8))
+       return 1;
+    else
+       return 0;
+}
+
+/*====================================================================*/
+
+static void add_socket(u_short port, int psock, int type)
+{
+    socket[sockets].ioaddr = port;
+    socket[sockets].psock = psock;
+    socket[sockets].type = type;
+    socket[sockets].flags = pcic[type].flags;
+    if (is_alive(sockets))
+       socket[sockets].flags |= IS_ALIVE;
+    sockets++;
+}
+
+static void add_pcic(int ns, int type)
+{
+    u_int mask = 0, i, base;
+    int use_pci = 0, isa_irq = 0;
+    socket_info_t *t = &socket[sockets-ns];
+
+    base = sockets-ns;
+    if (t->ioaddr > 0) request_region(t->ioaddr, 2, "i82365");
+    
+    if (base == 0) printk("\n");
+    printk(KERN_INFO "  %s", pcic[type].name);
+#ifdef CONFIG_PCI
+    if (t->flags & IS_UNKNOWN)
+       printk(" [0x%04x 0x%04x]", t->vendor, t->device);
+    if (t->flags & IS_CARDBUS)
+       printk(" PCI-to-CardBus at bus %d slot %d, mem 0x%08x",
+              t->bus, PCI_SLOT(t->devfn), t->cb_phys);
+    else if (t->flags & IS_PCI)
+       printk(" PCI-to-PCMCIA at bus %d slot %d, port %#x",
+              t->bus, PCI_SLOT(t->devfn), t->ioaddr);
+    else
+#endif
+       printk(" ISA-to-PCMCIA at port %#x ofs 0x%02x",
+              t->ioaddr, t->psock*0x40);
+    printk(", %d socket%s\n", ns, ((ns > 1) ? "s" : ""));
+
+#ifdef CONFIG_ISA
+    /* Set host options, build basic interrupt mask */
+    if (irq_list[0] == -1)
+       mask = irq_mask;
+    else
+       for (i = mask = 0; i < 16; i++)
+           mask |= (1<<irq_list[i]);
+#endif
+    mask &= I365_MASK & set_host_opts(base, ns);
+#ifdef CONFIG_ISA
+    /* Scan for ISA interrupts */
+    mask = isa_scan(base, mask);
+#else
+    printk(KERN_INFO "    PCI card interrupts,");
+#endif
+    
+#ifdef CONFIG_PCI
+    /* Can we use a PCI interrupt for card status changes? */
+    if (pci_csc && t->cap.pci_irq) {
+       for (i = 0; i < ns; i++)
+           if (_check_irq(t[i].cap.pci_irq, SA_SHIRQ)) break;
+       if (i == ns) {
+           use_pci = 1;
+           printk(" PCI status changes\n");
+       }
+    }
+#endif
+    
+#ifdef CONFIG_ISA
+    /* Poll if only two interrupts available */
+    if (!use_pci && !poll_interval) {
+       u_int tmp = (mask & (mask-1));
+       if ((tmp & (tmp-1)) == 0)
+           poll_interval = HZ;
+    }
+    /* Only try an ISA cs_irq if this is the first controller */
+    if (!use_pci && !grab_irq && (cs_irq || !poll_interval)) {
+       /* Avoid irq 12 unless it is explicitly requested */
+       u_int cs_mask = mask & ((cs_irq) ? (1<<cs_irq) : ~(1<<12));
+       for (cs_irq = 15; cs_irq > 0; cs_irq--)
+           if ((cs_mask & (1 << cs_irq)) &&
+               (_check_irq(cs_irq, 0) == 0))
+               break;
+       if (cs_irq) {
+           grab_irq = 1;
+           isa_irq = cs_irq;
+           printk(" status change on irq %d\n", cs_irq);
+       }
+    }
+#endif
+    
+    if (!use_pci && !isa_irq) {
+       if (poll_interval == 0)
+           poll_interval = HZ;
+       printk(" polling interval = %d ms\n",
+              poll_interval * 1000 / HZ);
+       
+    }
+    
+    /* Update socket interrupt information, capabilities */
+    for (i = 0; i < ns; i++) {
+       t[i].cap.features |= SS_CAP_PCCARD;
+       t[i].cap.map_size = 0x1000;
+       t[i].cap.irq_mask = mask;
+       if (pci_int && t[i].cap.pci_irq)
+           t[i].cap.irq_mask |= (1 << t[i].cap.pci_irq);
+       t[i].cs_irq = isa_irq;
+#ifdef CONFIG_PCI
+       if (t[i].flags & IS_CARDBUS) {
+           t[i].cap.features |= SS_CAP_CARDBUS;
+           cb_set_irq_mode(i, pci_csc && t[i].cap.pci_irq,
+                           pci_int && t[i].cap.pci_irq);
+       }
+#endif
+    }
+
+} /* add_pcic */
+
+/*====================================================================*/
+
+#ifdef CONFIG_PCI
+
+typedef struct pci_dev *pci_id_t;
+static int pci_lookup(u_int class, pci_id_t *id,
+                     u_char *bus, u_char *devfn)
+{
+    if ((*id = pci_find_class(class<<8, *id)) != NULL) {
+       *bus = (*id)->bus->number;
+       *devfn = (*id)->devfn;
+       return 0;
+    } else return -1;
+}
+
+static void add_pci_bridge(int type, u_char bus, u_char devfn,
+                          u_short v, u_short d)
+{
+    socket_info_t *s = &socket[sockets];
+    u_short i, ns;
+    u_int addr;
+
+    if (type == PCIC_COUNT) type = IS_UNK_PCI;
+    pci_readl(bus, devfn, PCI_BASE_ADDRESS_0, &addr);
+    addr &= ~0x1;
+    pci_writew(bus, devfn, PCI_COMMAND, CMD_DFLT);
+    for (i = ns = 0; i < ((type == IS_I82092AA) ? 4 : 2); i++) {
+       s->bus = bus; s->devfn = devfn;
+       s->vendor = v; s->device = d;
+       add_socket(addr, i, type);
+       ns++; s++;
+    }
+    add_pcic(ns, type);
+}
+
+static void add_cb_bridge(int type, u_char bus, u_char devfn,
+                         u_short v, u_short d0)
+{
+    socket_info_t *s = &socket[sockets];
+    u_short d, ns;
+    u_char a, b, r, max;
+    
+    /* PCI bus enumeration is broken on some systems */
+    for (ns = 0; ns < sockets; ns++)
+       if ((socket[ns].bus == bus) && (socket[ns].devfn == devfn))
+           return;
+    
+    if (type == PCIC_COUNT) type = IS_UNK_CARDBUS;
+    pci_readb(bus, devfn, PCI_HEADER_TYPE, &a);
+    pci_readb(bus, devfn, PCI_CLASS_REVISION, &r);
+    max = (a & 0x80) ? 8 : 1;
+    for (ns = 0; ns < max; ns++, s++, devfn++) {
+       if (pci_readw(bus, devfn, PCI_DEVICE_ID, &d) || (d != d0))
+           break;
+       s->bus = bus; s->devfn = devfn;
+       s->vendor = v; s->device = d; s->revision = r;
+       
+       /* Check for power management capabilities */
+       pci_readb(bus, devfn, PCI_STATUS, &a);
+       if (a & PCI_STATUS_CAPLIST) {
+           pci_readb(bus, devfn, PCI_CB_CAPABILITY_POINTER, &b);
+           while (b != 0) {
+               pci_readb(bus, devfn, b+PCI_CAPABILITY_ID, &a);
+               if (a == PCI_CAPABILITY_PM) {
+                   s->pmcs = b + PCI_PM_CONTROL_STATUS;
+                   break;
+               }
+               pci_readb(bus, devfn, b+PCI_NEXT_CAPABILITY, &b);
+           }
+       }
+       /* If capability exists, make sure we're in D0 state */
+       if (s->pmcs)
+           pci_writew(bus, devfn, s->pmcs, PCI_PMCS_PWR_STATE_D0);
+       
+       /* Map CardBus registers if they are not already mapped */
+       pci_writel(bus, devfn, CB_LEGACY_MODE_BASE, 0);
+       pci_readl(bus, devfn, PCI_BASE_ADDRESS_0, &s->cb_phys);
+       if (s->cb_phys == 0) {
+           int i;
+           for (i = 0; i < sizeof(cb_mem_base)/sizeof(u_int); i++) {
+               s->cb_phys = cb_mem_base[i];
+               s->cb_virt = ioremap(s->cb_phys, 0x1000);
+               pci_writel(bus, devfn, PCI_BASE_ADDRESS_0, s->cb_phys);
+               /* Simple sanity checks */
+               if (!(readb(s->cb_virt+0x800+I365_IDENT) & 0x70) &&
+                   !(readb(s->cb_virt+0x800+I365_CSC) &&
+                     readb(s->cb_virt+0x800+I365_CSC) &&
+                     readb(s->cb_virt+0x800+I365_CSC)))
+                   break;
+               iounmap(s->cb_virt);
+           }
+           if (i == sizeof(cb_mem_base)/sizeof(u_int)) {
+               pci_writel(bus, devfn, PCI_BASE_ADDRESS_0, 0);
+               printk("\n");
+               printk(KERN_NOTICE "  Bridge register mapping failed:"
+                      " check cb_mem_base setting\n");
+               break;
+           }
+           cb_mem_base[0] = cb_mem_base[i] + PAGE_SIZE;
+       } else {
+           s->cb_virt = ioremap(s->cb_phys, 0x1000);
+       }
+       
+       request_mem_region(s->cb_phys, 0x1000, "i82365");
+       add_socket(0, 0, type);
+    }
+    if (ns == 0) return;
+    
+    s -= ns;
+    if (ns == 2) {
+       /* Nasty special check for bad bus mapping */
+       pci_readb(bus, s[0].devfn, CB_CARDBUS_BUS, &a);
+       pci_readb(bus, s[1].devfn, CB_CARDBUS_BUS, &b);
+       if (a == b) {
+           pci_writeb(bus, s[0].devfn, CB_CARDBUS_BUS, 0);
+           pci_writeb(bus, s[1].devfn, CB_CARDBUS_BUS, 0);
+       }
+    }
+    add_pcic(ns, type);
+
+    /* Re-do card type & voltage detection */
+    cb_writel(sockets-ns, CB_SOCKET_FORCE, CB_SF_CVSTEST);
+    current->state = TASK_INTERRUPTIBLE;
+    schedule_timeout(HZ/5);
+
+    /* Set up PCI bus bridge structures if needed */
+    for (a = 0; a < ns; a++) {
+       struct pci_dev *self = pci_find_slot(bus, s[a].devfn);
+       struct pci_bus *child, *parent = self->bus;
+       for (child = parent->children; child; child = child->next)
+           if (child->number == s[a].cap.cardbus) break;
+       if (!child) {
+           child = kmalloc(sizeof(struct pci_bus), GFP_KERNEL);
+           memset(child, 0, sizeof(struct pci_bus));
+           child->self = self;
+           child->primary = bus;
+           child->number = child->secondary = s[a].cap.cardbus;
+           child->subordinate = s[a].sub_bus;
+           child->parent = parent;
+           child->next = parent->children;
+       }
+       s[a].cap.cb_bus = parent->children = child;
+    }
+}
+
+static void pci_probe(u_int class, void (add_fn)(int, u_char, u_char,
+                                                u_short, u_short))
+{
+    u_short i, v, d;
+    u_char bus, devfn;
+    pci_id_t id;
+    
+    id = 0;
+    while (pci_lookup(class, &id, &bus, &devfn) == 0) {
+       if (PCI_FUNC(devfn) != 0) continue;
+       pci_readw(bus, devfn, PCI_VENDOR_ID, &v);
+       pci_readw(bus, devfn, PCI_DEVICE_ID, &d);
+       for (i = 0; i < PCIC_COUNT; i++)
+           if ((pcic[i].vendor == v) && (pcic[i].device == d)) break;
+       add_fn(i, bus, devfn, v, d);
+    }
+}
+
+#endif /* CONFIG_PCI */
+
+/*====================================================================*/
+
+#ifdef CONFIG_ISA
+
+static void isa_probe(void)
+{
+    int i, j, sock, k;
+    int ns, id;
+    u_short port;
+
+    if (check_region(i365_base, 2) != 0) {
+       if (sockets == 0)
+           printk("port conflict at %#x\n", i365_base);
+       return;
+    }
+
+    id = identify(i365_base, 0);
+    if ((id == IS_I82365DF) && (identify(i365_base, 1) != id)) {
+       for (i = 0; i < 4; i++) {
+           if (i == ignore) continue;
+           port = i365_base + ((i & 1) << 2) + ((i & 2) << 1);
+           sock = (i & 1) << 1;
+           if (identify(port, sock) == IS_I82365DF) {
+               add_socket(port, sock, IS_VLSI);
+               add_pcic(1, IS_VLSI);
+           }
+       }
+    } else {
+       for (i = 0; i < (extra_sockets ? 8 : 4); i += 2) {
+           port = i365_base + 2*(i>>2);
+           sock = (i & 3);
+           id = identify(port, sock);
+           if (id < 0) continue;
+
+           for (j = ns = 0; j < 2; j++) {
+               /* Does the socket exist? */
+               if ((ignore == i+j) || (identify(port, sock+j) < 0))
+                   continue;
+               /* Check for bad socket decode */
+               for (k = 0; k <= sockets; k++)
+                   i365_set(k, I365_MEM(0)+I365_W_OFF, k);
+               for (k = 0; k <= sockets; k++)
+                   if (i365_get(k, I365_MEM(0)+I365_W_OFF) != k)
+                       break;
+               if (k <= sockets) break;
+               add_socket(port, sock+j, id); ns++;
+           }
+           if (ns != 0) add_pcic(ns, id);
+       }
+    }
+}
+
+#endif
+
+/*====================================================================*/
+
+static int pcic_init(void)
+{
+    DEBUG(0, ("%s\n", version));
+    printk(KERN_INFO "Intel PCIC probe: ");
+    sockets = 0;
+
+#ifdef CONFIG_PCI
+    if (do_pci_probe && pcibios_present()) {
+       pci_probe(PCI_CLASS_BRIDGE_CARDBUS, add_cb_bridge);
+       pci_probe(PCI_CLASS_BRIDGE_PCMCIA, add_pci_bridge);
+    }
+#endif
+
+#ifdef CONFIG_ISA
+    isa_probe();
+#endif
+       
+    if (sockets == 0) {
+       printk("not found.\n");
+       return -ENODEV;
+    }
+    
+    /* Set up interrupt handler, and/or polling */
+#ifdef CONFIG_ISA
+    if (grab_irq != 0)
+       request_irq(cs_irq, pcic_interrupt, 0, "i82365", NULL);
+#endif
+#ifdef CONFIG_PCI
+    if (pci_csc) {
+       u_int i, irq, mask = 0;
+       for (i = 0; i < sockets; i++) {
+           irq = socket[i].cap.pci_irq;
+           if (irq && !(mask & (1<<irq)))
+               request_irq(irq, pcic_interrupt, SA_SHIRQ, "i82365", NULL);
+           mask |= (1<<irq);
+       }
+    }
+#endif
+    
+    if (register_ss_entry(sockets, &pcic_service) != 0)
+       printk(KERN_NOTICE "i82365: register_ss_entry() failed\n");
+
+    /* Finally, schedule a polling interrupt */
+    if (poll_interval != 0) {
+       poll_timer.function = pcic_interrupt_wrapper;
+       poll_timer.data = 0;
+       poll_timer.prev = poll_timer.next = NULL;
+       poll_timer.expires = jiffies + poll_interval;
+       add_timer(&poll_timer);
+    }
+    
+    return 0;
+    
+} /* pcic_init */
+  
+/*====================================================================*/
+
+static void pcic_finish(void)
+{
+    int i;
+#ifdef CONFIG_PROC_FS
+    for (i = 0; i < sockets; i++) pcic_proc_remove(i);
+#endif
+    unregister_ss_entry(&pcic_service);
+    if (poll_interval != 0)
+       del_timer(&poll_timer);
+#ifdef CONFIG_ISA
+    if (grab_irq != 0)
+       free_irq(cs_irq, NULL);
+#endif
+#ifdef CONFIG_PCI
+    if (pci_csc) {
+       u_int irq, mask = 0;
+       for (i = 0; i < sockets; i++) {
+           irq = socket[i].cap.pci_irq;
+           if (irq && !(mask & (1<<irq)))
+               free_irq(irq, NULL);
+           mask |= (1<<irq);
+       }
+    }
+#endif
+    for (i = 0; i < sockets; i++) {
+       i365_set(i, I365_CSCINT, 0);
+#ifdef CONFIG_PCI
+       if (socket[i].cb_virt) {
+           iounmap(socket[i].cb_virt);
+           release_mem_region(socket[i].cb_phys, 0x1000);
+       } else
+#endif
+           release_region(socket[i].ioaddr, 2);
+    }
+} /* pcic_finish */
+
+/*====================================================================*/
+
+static void pcic_interrupt_wrapper(u_long data)
+{
+    pcic_interrupt(0, NULL, NULL);
+    poll_timer.expires = jiffies + poll_interval;
+    add_timer(&poll_timer);
+}
+
+static void pcic_interrupt(int irq, void *dev, struct pt_regs *regs)
+{
+    int i, j, csc;
+    u_int events, active;
+#ifdef CONFIG_ISA
+    u_long flags = 0;
+#endif
+    
+    DEBUG(4, ("i82365: pcic_interrupt(%d)\n", irq));
+
+    for (j = 0; j < 20; j++) {
+       active = 0;
+       for (i = 0; i < sockets; i++) {
+           if ((socket[i].cs_irq != irq) &&
+               (socket[i].cap.pci_irq != irq))
+               continue;
+#ifdef CONFIG_ISA
+           if (!(socket[i].flags & IS_CARDBUS))
+               spin_lock_irqsave(&isa_lock, flags);
+#endif
+           csc = i365_get(i, I365_CSC);
+           if ((csc == 0) || (!socket[i].handler) ||
+               (i365_get(i, I365_IDENT) & 0x70)) {
+#ifdef CONFIG_ISA
+               if (!(socket[i].flags & IS_CARDBUS))
+                   spin_unlock_irqrestore(&isa_lock, flags);
+#endif
+               continue;
+           }
+           events = (csc & I365_CSC_DETECT) ? SS_DETECT : 0;
+           if (i365_get(i, I365_INTCTL) & I365_PC_IOCARD)
+               events |= (csc & I365_CSC_STSCHG) ? SS_STSCHG : 0;
+           else {
+               events |= (csc & I365_CSC_BVD1) ? SS_BATDEAD : 0;
+               events |= (csc & I365_CSC_BVD2) ? SS_BATWARN : 0;
+               events |= (csc & I365_CSC_READY) ? SS_READY : 0;
+           }
+#ifdef CONFIG_ISA
+           if (!(socket[i].flags & IS_CARDBUS))
+               spin_unlock_irqrestore(&isa_lock, flags);
+#endif
+           DEBUG(2, ("i82365: socket %d event 0x%02x\n", i, events));
+           if (events)
+               socket[i].handler(socket[i].info, events);
+           active |= events;
+       }
+       if (!active) break;
+    }
+    if (j == 20)
+       printk(KERN_NOTICE "i82365: infinite loop in interrupt handler\n");
+
+    DEBUG(4, ("i82365: interrupt done\n"));
+} /* pcic_interrupt */
+
+/*====================================================================*/
+
+static int pcic_register_callback(u_short sock, ss_callback_t *call)
+{
+    if (call == NULL) {
+       socket[sock].handler = NULL;
+       MOD_DEC_USE_COUNT;
+    } else {
+       MOD_INC_USE_COUNT;
+       socket[sock].handler = call->handler;
+       socket[sock].info = call->info;
+    }
+    return 0;
+} /* pcic_register_callback */
+
+/*====================================================================*/
+
+static int pcic_inquire_socket(u_short sock, socket_cap_t *cap)
+{
+    *cap = socket[sock].cap;
+    return 0;
+} /* pcic_inquire_socket */
+
+/*====================================================================*/
+
+static int i365_get_status(u_short sock, u_int *value)
+{
+    u_int status;
+    
+    status = i365_get(sock, I365_STATUS);
+    *value = ((status & I365_CS_DETECT) == I365_CS_DETECT)
+       ? SS_DETECT : 0;
+    if (i365_get(sock, I365_INTCTL) & I365_PC_IOCARD)
+       *value |= (status & I365_CS_STSCHG) ? 0 : SS_STSCHG;
+    else {
+       *value |= (status & I365_CS_BVD1) ? 0 : SS_BATDEAD;
+       *value |= (status & I365_CS_BVD2) ? 0 : SS_BATWARN;
+    }
+    *value |= (status & I365_CS_WRPROT) ? SS_WRPROT : 0;
+    *value |= (status & I365_CS_READY) ? SS_READY : 0;
+    *value |= (status & I365_CS_POWERON) ? SS_POWERON : 0;
+
+#ifdef CONFIG_PCI
+    if (socket[sock].flags & IS_CARDBUS) {
+       status = cb_readl(sock, CB_SOCKET_STATE);
+#ifndef CONFIG_CARDBUS
+       *value |= (status & CB_SS_32BIT) ? SS_CARDBUS : 0;
+#endif
+       *value |= (status & CB_SS_3VCARD) ? SS_3VCARD : 0;
+       *value |= (status & CB_SS_XVCARD) ? SS_XVCARD : 0;
+    } else if (socket[sock].flags & IS_O2MICRO) {
+       status = i365_get(sock, O2_MODE_B);
+       *value |= (status & O2_MODE_B_VS1) ? 0 : SS_3VCARD;
+       *value |= (status & O2_MODE_B_VS2) ? 0 : SS_XVCARD;
+    }
+#endif
+#ifdef CONFIG_ISA
+    if (socket[sock].type == IS_VG469) {
+       status = i365_get(sock, VG469_VSENSE);
+       if (socket[sock].psock & 1) {
+           *value |= (status & VG469_VSENSE_B_VS1) ? 0 : SS_3VCARD;
+           *value |= (status & VG469_VSENSE_B_VS2) ? 0 : SS_XVCARD;
+       } else {
+           *value |= (status & VG469_VSENSE_A_VS1) ? 0 : SS_3VCARD;
+           *value |= (status & VG469_VSENSE_A_VS2) ? 0 : SS_XVCARD;
+       }
+    }
+#endif
+    
+    DEBUG(1, ("i82365: GetStatus(%d) = %#4.4x\n", sock, *value));
+    return 0;
+} /* i365_get_status */
+
+/*====================================================================*/
+
+static int i365_get_socket(u_short sock, socket_state_t *state)
+{
+    socket_info_t *t = &socket[sock];
+    u_char reg, vcc, vpp;
+    
+    reg = i365_get(sock, I365_POWER);
+    state->flags = (reg & I365_PWR_AUTO) ? SS_PWR_AUTO : 0;
+    state->flags |= (reg & I365_PWR_OUT) ? SS_OUTPUT_ENA : 0;
+    vcc = reg & I365_VCC_MASK; vpp = reg & I365_VPP1_MASK;
+    state->Vcc = state->Vpp = 0;
+#ifdef CONFIG_PCI
+    if (t->flags & IS_CARDBUS) {
+       cb_get_power(sock, state);
+    } else
+#endif
+    if (t->flags & IS_CIRRUS) {
+       if (i365_get(sock, PD67_MISC_CTL_1) & PD67_MC1_VCC_3V) {
+           if (reg & I365_VCC_5V) state->Vcc = 33;
+           if (vpp == I365_VPP1_5V) state->Vpp = 33;
+       } else {
+           if (reg & I365_VCC_5V) state->Vcc = 50;
+           if (vpp == I365_VPP1_5V) state->Vpp = 50;
+       }
+       if (vpp == I365_VPP1_12V) state->Vpp = 120;
+    } else if (t->flags & IS_VG_PWR) {
+       if (i365_get(sock, VG469_VSELECT) & VG469_VSEL_VCC) {
+           if (reg & I365_VCC_5V) state->Vcc = 33;
+           if (vpp == I365_VPP1_5V) state->Vpp = 33;
+       } else {
+           if (reg & I365_VCC_5V) state->Vcc = 50;
+           if (vpp == I365_VPP1_5V) state->Vpp = 50;
+       }
+       if (vpp == I365_VPP1_12V) state->Vpp = 120;
+    } else if (t->flags & IS_DF_PWR) {
+       if (vcc == I365_VCC_3V) state->Vcc = 33;
+       if (vcc == I365_VCC_5V) state->Vcc = 50;
+       if (vpp == I365_VPP1_5V) state->Vpp = 50;
+       if (vpp == I365_VPP1_12V) state->Vpp = 120;
+    } else {
+       if (reg & I365_VCC_5V) {
+           state->Vcc = 50;
+           if (vpp == I365_VPP1_5V) state->Vpp = 50;
+           if (vpp == I365_VPP1_12V) state->Vpp = 120;
+       }
+    }
+
+    /* IO card, RESET flags, IO interrupt */
+    reg = i365_get(sock, I365_INTCTL);
+    state->flags |= (reg & I365_PC_RESET) ? 0 : SS_RESET;
+    if (reg & I365_PC_IOCARD) state->flags |= SS_IOCARD;
+#ifdef CONFIG_PCI
+    if (cb_get_irq_mode(sock) != 0)
+       state->io_irq = t->cap.pci_irq;
+    else
+#endif
+       state->io_irq = reg & I365_IRQ_MASK;
+    
+    /* speaker control */
+    if (t->flags & IS_CIRRUS) {
+       if (i365_get(sock, PD67_MISC_CTL_1) & PD67_MC1_SPKR_ENA)
+           state->flags |= SS_SPKR_ENA;
+    }
+    
+    /* Card status change mask */
+    reg = i365_get(sock, I365_CSCINT);
+    state->csc_mask = (reg & I365_CSC_DETECT) ? SS_DETECT : 0;
+    if (state->flags & SS_IOCARD)
+       state->csc_mask |= (reg & I365_CSC_STSCHG) ? SS_STSCHG : 0;
+    else {
+       state->csc_mask |= (reg & I365_CSC_BVD1) ? SS_BATDEAD : 0;
+       state->csc_mask |= (reg & I365_CSC_BVD2) ? SS_BATWARN : 0;
+       state->csc_mask |= (reg & I365_CSC_READY) ? SS_READY : 0;
+    }
+    
+    DEBUG(1, ("i82365: GetSocket(%d) = flags %#3.3x, Vcc %d, Vpp %d, "
+             "io_irq %d, csc_mask %#2.2x\n", sock, state->flags,
+             state->Vcc, state->Vpp, state->io_irq, state->csc_mask));
+    return 0;
+} /* i365_get_socket */
+
+/*====================================================================*/
+
+static int i365_set_socket(u_short sock, socket_state_t *state)
+{
+    socket_info_t *t = &socket[sock];
+    u_char reg;
+    
+    DEBUG(1, ("i82365: SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, "
+             "io_irq %d, csc_mask %#2.2x)\n", sock, state->flags,
+             state->Vcc, state->Vpp, state->io_irq, state->csc_mask));
+    
+    /* First set global controller options */
+#ifdef CONFIG_PCI
+    if ((t->flags & IS_CARDBUS) && t->cap.pci_irq)
+       cb_set_irq_mode(sock, pci_csc,
+                       (t->cap.pci_irq == state->io_irq));
+    t->bcr &= ~CB_BCR_CB_RESET;
+#endif
+    set_host_state(sock);
+    
+    /* IO card, RESET flag, IO interrupt */
+    reg = t->intr;
+    if (state->io_irq != t->cap.pci_irq) reg |= state->io_irq;
+    reg |= (state->flags & SS_RESET) ? 0 : I365_PC_RESET;
+    reg |= (state->flags & SS_IOCARD) ? I365_PC_IOCARD : 0;
+    i365_set(sock, I365_INTCTL, reg);
+    
+    reg = I365_PWR_NORESET;
+    if (state->flags & SS_PWR_AUTO) reg |= I365_PWR_AUTO;
+    if (state->flags & SS_OUTPUT_ENA) reg |= I365_PWR_OUT;
+
+#ifdef CONFIG_PCI
+    if (t->flags & IS_CARDBUS) {
+       cb_set_power(sock, state);
+       reg |= i365_get(sock, I365_POWER) &
+           (I365_VCC_MASK|I365_VPP1_MASK);
+    } else
+#endif
+    if (t->flags & IS_CIRRUS) {
+       if (state->Vpp != 0) {
+           if (state->Vpp == 120)
+               reg |= I365_VPP1_12V;
+           else if (state->Vpp == state->Vcc)
+               reg |= I365_VPP1_5V;
+           else return -EINVAL;
+       }
+       if (state->Vcc != 0) {
+           reg |= I365_VCC_5V;
+           if (state->Vcc == 33)
+               i365_bset(sock, PD67_MISC_CTL_1, PD67_MC1_VCC_3V);
+           else if (state->Vcc == 50)
+               i365_bclr(sock, PD67_MISC_CTL_1, PD67_MC1_VCC_3V);
+           else return -EINVAL;
+       }
+    } else if (t->flags & IS_VG_PWR) {
+       if (state->Vpp != 0) {
+           if (state->Vpp == 120)
+               reg |= I365_VPP1_12V;
+           else if (state->Vpp == state->Vcc)
+               reg |= I365_VPP1_5V;
+           else return -EINVAL;
+       }
+       if (state->Vcc != 0) {
+           reg |= I365_VCC_5V;
+           if (state->Vcc == 33)
+               i365_bset(sock, VG469_VSELECT, VG469_VSEL_VCC);
+           else if (state->Vcc == 50)
+               i365_bclr(sock, VG469_VSELECT, VG469_VSEL_VCC);
+           else return -EINVAL;
+       }
+    } else if (t->flags & IS_DF_PWR) {
+       switch (state->Vcc) {
+       case 0:         break;
+       case 33:        reg |= I365_VCC_3V; break;
+       case 50:        reg |= I365_VCC_5V; break;
+       default:        return -EINVAL;
+       }
+       switch (state->Vpp) {
+       case 0:         break;
+       case 50:        reg |= I365_VPP1_5V; break;
+       case 120:       reg |= I365_VPP1_12V; break;
+       default:        return -EINVAL;
+       }
+    } else {
+       switch (state->Vcc) {
+       case 0:         break;
+       case 50:        reg |= I365_VCC_5V; break;
+       default:        return -EINVAL;
+       }
+       switch (state->Vpp) {
+       case 0:         break;
+       case 50:        reg |= I365_VPP1_5V | I365_VPP2_5V; break;
+       case 120:       reg |= I365_VPP1_12V | I365_VPP2_12V; break;
+       default:        return -EINVAL;
+       }
+    }
+    
+    if (reg != i365_get(sock, I365_POWER))
+       i365_set(sock, I365_POWER, reg);
+
+    /* Chipset-specific functions */
+    if (t->flags & IS_CIRRUS) {
+       /* Speaker control */
+       i365_bflip(sock, PD67_MISC_CTL_1, PD67_MC1_SPKR_ENA,
+                  state->flags & SS_SPKR_ENA);
+    }
+    
+    /* Card status change interrupt mask */
+    reg = t->cs_irq << 4;
+    if (state->csc_mask & SS_DETECT) reg |= I365_CSC_DETECT;
+    if (state->flags & SS_IOCARD) {
+       if (state->csc_mask & SS_STSCHG) reg |= I365_CSC_STSCHG;
+    } else {
+       if (state->csc_mask & SS_BATDEAD) reg |= I365_CSC_BVD1;
+       if (state->csc_mask & SS_BATWARN) reg |= I365_CSC_BVD2;
+       if (state->csc_mask & SS_READY) reg |= I365_CSC_READY;
+    }
+    i365_set(sock, I365_CSCINT, reg);
+    i365_get(sock, I365_CSC);
+    
+    return 0;
+} /* i365_set_socket */
+
+/*====================================================================*/
+
+static int i365_get_io_map(u_short sock, struct pccard_io_map *io)
+{
+    u_char map, ioctl, addr;
+    
+    map = io->map;
+    if (map > 1) return -EINVAL;
+    io->start = i365_get_pair(sock, I365_IO(map)+I365_W_START);
+    io->stop = i365_get_pair(sock, I365_IO(map)+I365_W_STOP);
+    ioctl = i365_get(sock, I365_IOCTL);
+    addr = i365_get(sock, I365_ADDRWIN);
+    io->speed = to_ns(ioctl & I365_IOCTL_WAIT(map)) ? 1 : 0;
+    io->flags  = (addr & I365_ENA_IO(map)) ? MAP_ACTIVE : 0;
+    io->flags |= (ioctl & I365_IOCTL_0WS(map)) ? MAP_0WS : 0;
+    io->flags |= (ioctl & I365_IOCTL_16BIT(map)) ? MAP_16BIT : 0;
+    io->flags |= (ioctl & I365_IOCTL_IOCS16(map)) ? MAP_AUTOSZ : 0;
+    DEBUG(1, ("i82365: GetIOMap(%d, %d) = %#2.2x, %d ns, "
+             "%#4.4x-%#4.4x\n", sock, map, io->flags, io->speed,
+             io->start, io->stop));
+    return 0;
+} /* i365_get_io_map */
+
+/*====================================================================*/
+
+static int i365_set_io_map(u_short sock, struct pccard_io_map *io)
+{
+    u_char map, ioctl;
+    
+    DEBUG(1, ("i82365: SetIOMap(%d, %d, %#2.2x, %d ns, "
+             "%#4.4x-%#4.4x)\n", sock, io->map, io->flags,
+             io->speed, io->start, io->stop));
+    map = io->map;
+    if ((map > 1) || (io->start > 0xffff) || (io->stop > 0xffff) ||
+       (io->stop < io->start)) return -EINVAL;
+    /* Turn off the window before changing anything */
+    if (i365_get(sock, I365_ADDRWIN) & I365_ENA_IO(map))
+       i365_bclr(sock, I365_ADDRWIN, I365_ENA_IO(map));
+    i365_set_pair(sock, I365_IO(map)+I365_W_START, io->start);
+    i365_set_pair(sock, I365_IO(map)+I365_W_STOP, io->stop);
+    ioctl = i365_get(sock, I365_IOCTL) & ~I365_IOCTL_MASK(map);
+    if (io->speed) ioctl |= I365_IOCTL_WAIT(map);
+    if (io->flags & MAP_0WS) ioctl |= I365_IOCTL_0WS(map);
+    if (io->flags & MAP_16BIT) ioctl |= I365_IOCTL_16BIT(map);
+    if (io->flags & MAP_AUTOSZ) ioctl |= I365_IOCTL_IOCS16(map);
+    i365_set(sock, I365_IOCTL, ioctl);
+    /* Turn on the window if necessary */
+    if (io->flags & MAP_ACTIVE)
+       i365_bset(sock, I365_ADDRWIN, I365_ENA_IO(map));
+    return 0;
+} /* i365_set_io_map */
+
+/*====================================================================*/
+
+static int i365_get_mem_map(u_short sock, struct pccard_mem_map *mem)
+{
+    u_short base, i;
+    u_char map, addr;
+    
+    map = mem->map;
+    if (map > 4) return -EINVAL;
+    addr = i365_get(sock, I365_ADDRWIN);
+    mem->flags = (addr & I365_ENA_MEM(map)) ? MAP_ACTIVE : 0;
+    base = I365_MEM(map);
+    
+    i = i365_get_pair(sock, base+I365_W_START);
+    mem->flags |= (i & I365_MEM_16BIT) ? MAP_16BIT : 0;
+    mem->flags |= (i & I365_MEM_0WS) ? MAP_0WS : 0;
+    mem->sys_start += ((u_long)(i & 0x0fff) << 12);
+    
+    i = i365_get_pair(sock, base+I365_W_STOP);
+    mem->speed  = (i & I365_MEM_WS0) ? 1 : 0;
+    mem->speed += (i & I365_MEM_WS1) ? 2 : 0;
+    mem->speed = to_ns(mem->speed);
+    mem->sys_stop = ((u_long)(i & 0x0fff) << 12) + 0x0fff;
+    
+    i = i365_get_pair(sock, base+I365_W_OFF);
+    mem->flags |= (i & I365_MEM_WRPROT) ? MAP_WRPROT : 0;
+    mem->flags |= (i & I365_MEM_REG) ? MAP_ATTRIB : 0;
+    mem->card_start = ((u_int)(i & 0x3fff) << 12) + mem->sys_start;
+    mem->card_start &= 0x3ffffff;
+
+#ifdef CONFIG_PCI
+    /* Take care of high byte, for PCI controllers */
+    if (socket[sock].type == IS_PD6729) {
+       i365_set(sock, PD67_EXT_INDEX, PD67_MEM_PAGE(map));
+       addr = i365_get(sock, PD67_EXT_DATA) << 24;
+    } else if (socket[sock].flags & IS_CARDBUS) {
+       addr = i365_get(sock, CB_MEM_PAGE(map)) << 24;
+       mem->sys_stop += addr; mem->sys_start += addr;
+    }
+#endif
+    
+    DEBUG(1, ("i82365: GetMemMap(%d, %d) = %#2.2x, %d ns, %#5.5lx-%#5."
+             "5lx, %#5.5x\n", sock, mem->map, mem->flags, mem->speed,
+             mem->sys_start, mem->sys_stop, mem->card_start));
+    return 0;
+} /* i365_get_mem_map */
+
+/*====================================================================*/
+  
+static int i365_set_mem_map(u_short sock, struct pccard_mem_map *mem)
+{
+    u_short base, i;
+    u_char map;
+    
+    DEBUG(1, ("i82365: SetMemMap(%d, %d, %#2.2x, %d ns, %#5.5lx-%#5.5"
+             "lx, %#5.5x)\n", sock, mem->map, mem->flags, mem->speed,
+             mem->sys_start, mem->sys_stop, mem->card_start));
+
+    map = mem->map;
+    if ((map > 4) || (mem->card_start > 0x3ffffff) ||
+       (mem->sys_start > mem->sys_stop) || (mem->speed > 1000))
+       return -EINVAL;
+    if (!(socket[sock].flags & (IS_PCI | IS_CARDBUS)) &&
+       ((mem->sys_start > 0xffffff) || (mem->sys_stop > 0xffffff)))
+       return -EINVAL;
+       
+    /* Turn off the window before changing anything */
+    if (i365_get(sock, I365_ADDRWIN) & I365_ENA_MEM(map))
+       i365_bclr(sock, I365_ADDRWIN, I365_ENA_MEM(map));
+
+#ifdef CONFIG_PCI
+    /* Take care of high byte, for PCI controllers */
+    if (socket[sock].type == IS_PD6729) {
+       i365_set(sock, PD67_EXT_INDEX, PD67_MEM_PAGE(map));
+       i365_set(sock, PD67_EXT_DATA, (mem->sys_start >> 24));
+    } else if (socket[sock].flags & IS_CARDBUS)
+       i365_set(sock, CB_MEM_PAGE(map), mem->sys_start >> 24);
+#endif
+    
+    base = I365_MEM(map);
+    i = (mem->sys_start >> 12) & 0x0fff;
+    if (mem->flags & MAP_16BIT) i |= I365_MEM_16BIT;
+    if (mem->flags & MAP_0WS) i |= I365_MEM_0WS;
+    i365_set_pair(sock, base+I365_W_START, i);
+    
+    i = (mem->sys_stop >> 12) & 0x0fff;
+    switch (to_cycles(mem->speed)) {
+    case 0:    break;
+    case 1:    i |= I365_MEM_WS0; break;
+    case 2:    i |= I365_MEM_WS1; break;
+    default:   i |= I365_MEM_WS1 | I365_MEM_WS0; break;
+    }
+    i365_set_pair(sock, base+I365_W_STOP, i);
+    
+    i = ((mem->card_start - mem->sys_start) >> 12) & 0x3fff;
+    if (mem->flags & MAP_WRPROT) i |= I365_MEM_WRPROT;
+    if (mem->flags & MAP_ATTRIB) i |= I365_MEM_REG;
+    i365_set_pair(sock, base+I365_W_OFF, i);
+    
+    /* Turn on the window if necessary */
+    if (mem->flags & MAP_ACTIVE)
+       i365_bset(sock, I365_ADDRWIN, I365_ENA_MEM(map));
+    return 0;
+} /* i365_set_mem_map */
+
+/*======================================================================
+
+    Power control for Cardbus controllers: used both for 16-bit and
+    Cardbus cards.
+    
+======================================================================*/
+
+#ifdef CONFIG_PCI
+
+static void cb_get_power(u_short sock, socket_state_t *state)
+{
+    u_int reg = cb_readl(sock, CB_SOCKET_CONTROL);
+    state->Vcc = state->Vpp = 0;
+    switch (reg & CB_SC_VCC_MASK) {
+    case CB_SC_VCC_3V:         state->Vcc = 33; break;
+    case CB_SC_VCC_5V:         state->Vcc = 50; break;
+    }
+    switch (reg & CB_SC_VCC_MASK) {
+    case CB_SC_VPP_3V:         state->Vpp = 33; break;
+    case CB_SC_VPP_5V:         state->Vpp = 50; break;
+    case CB_SC_VPP_12V:                state->Vpp = 120; break;
+    }
+}
+
+static void cb_set_power(u_short sock, socket_state_t *state)
+{
+    u_int reg = 0;
+    switch (state->Vcc) {
+    case 33:           reg = CB_SC_VCC_3V; break;
+    case 50:           reg = CB_SC_VCC_5V; break;
+    default:           reg = 0; break;
+    }
+    switch (state->Vpp) {
+    case 33:           reg |= CB_SC_VPP_3V; break;
+    case 50:           reg |= CB_SC_VPP_5V; break;
+    case 120:          reg |= CB_SC_VPP_12V; break;
+    }
+    if (reg != cb_readl(sock, CB_SOCKET_CONTROL))
+       cb_writel(sock, CB_SOCKET_CONTROL, reg);
+}
+
+#endif
+
+/*======================================================================
+
+    All the stuff that is strictly for Cardbus cards goes here.
+    
+======================================================================*/
+
+#ifdef CONFIG_CARDBUS
+
+static int cb_get_status(u_short sock, u_int *value)
+{
+    u_int s;
+    s = cb_readl(sock, CB_SOCKET_STATE);
+    *value = ((s & CB_SS_32BIT) ? SS_CARDBUS : 0);
+    *value |= ((s & CB_SS_CCD1) || (s & CB_SS_CCD2)) ? 0 : SS_DETECT;
+    *value |= (s & CB_SS_CSTSCHG) ? SS_STSCHG : 0;
+    *value |= (s & CB_SS_PWRCYCLE) ? (SS_POWERON|SS_READY) : 0;
+    *value |= (s & CB_SS_3VCARD) ? SS_3VCARD : 0;
+    *value |= (s & CB_SS_XVCARD) ? SS_XVCARD : 0;
+    DEBUG(1, ("yenta: GetStatus(%d) = %#4.4x\n", sock, *value));
+    return 0;
+} /* cb_get_status */
+
+static int cb_get_socket(u_short sock, socket_state_t *state)
+{
+    socket_info_t *s = &socket[sock];
+    u_short bcr;
+
+    cb_get_power(sock, state);
+    pci_readw(s->bus, s->devfn, CB_BRIDGE_CONTROL, &bcr);
+    state->flags |= (bcr & CB_BCR_CB_RESET) ? SS_RESET : 0;
+    if (cb_get_irq_mode(sock) != 0)
+       state->io_irq = s->cap.pci_irq;
+    else
+       state->io_irq = i365_get(sock, I365_INTCTL) & I365_IRQ_MASK;
+    DEBUG(1, ("yenta: GetSocket(%d) = flags %#3.3x, Vcc %d, Vpp %d, "
+             "io_irq %d, csc_mask %#2.2x\n", sock, state->flags,
+             state->Vcc, state->Vpp, state->io_irq, state->csc_mask));
+    return 0;
+} /* cb_get_socket */
+
+static int cb_set_socket(u_short sock, socket_state_t *state)
+{
+    socket_info_t *s = &socket[sock];
+    u_int reg;
+    
+    DEBUG(1, ("yenta: SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, "
+             "io_irq %d, csc_mask %#2.2x)\n", sock, state->flags,
+             state->Vcc, state->Vpp, state->io_irq, state->csc_mask));
+    
+    /* First set global controller options */
+    if (s->cap.pci_irq)
+       cb_set_irq_mode(sock, pci_csc,
+                       (s->cap.pci_irq == state->io_irq));
+    s->bcr &= ~CB_BCR_CB_RESET;
+    s->bcr |= (state->flags & SS_RESET) ? CB_BCR_CB_RESET : 0;
+    set_host_state(sock);
+    
+    cb_set_power(sock, state);
+    
+    /* Handle IO interrupt using ISA routing */
+    reg = i365_get(sock, I365_INTCTL) & ~I365_IRQ_MASK;
+    if (state->io_irq != s->cap.pci_irq) reg |= state->io_irq;
+    i365_set(sock, I365_INTCTL, reg);
+    
+    /* Handle CSC mask */
+    reg = (socket[sock].cs_irq << 4);
+    if (state->csc_mask & SS_DETECT) reg |= I365_CSC_DETECT;
+    i365_set(sock, I365_CSCINT, reg);
+    i365_get(sock, I365_CSC);
+    
+    return 0;
+} /* cb_set_socket */
+
+static int cb_get_bridge(u_short sock, struct cb_bridge_map *m)
+{
+    socket_info_t *s = &socket[sock];
+    u_char map;
+    
+    map = m->map;
+    if (map > 1) return -EINVAL;
+    m->flags &= MAP_IOSPACE;
+    map += (m->flags & MAP_IOSPACE) ? 2 : 0;
+    pci_readl(s->bus, s->devfn, CB_MEM_BASE(map), &m->start);
+    pci_readl(s->bus, s->devfn, CB_MEM_LIMIT(map), &m->stop);
+    if (m->start || m->stop) {
+       m->flags |= MAP_ACTIVE;
+       m->stop |= (map > 1) ? 3 : 0x0fff;
+    }
+    if (map > 1) {
+       u_short bcr;
+       pci_readw(s->bus, s->devfn, CB_BRIDGE_CONTROL, &bcr);
+       m->flags |= (bcr & CB_BCR_PREFETCH(map)) ? MAP_PREFETCH : 0;
+    }
+    DEBUG(1, ("yenta: GetBridge(%d, %d) = %#2.2x, %#4.4x-%#4.4x\n",
+             sock, map, m->flags, m->start, m->stop));
+    return 0;
+}
+
+static int cb_set_bridge(u_short sock, struct cb_bridge_map *m)
+{
+    socket_info_t *s = &socket[sock];
+    u_char map;
+    
+    DEBUG(1, ("yenta: SetBridge(%d, %d, %#2.2x, %#4.4x-%#4.4x)\n",
+             sock, m->map, m->flags, m->start, m->stop));
+    map = m->map;
+    if (!(s->flags & IS_CARDBUS) || (map > 1) || (m->stop < m->start))
+       return -EINVAL;
+    if (m->flags & MAP_IOSPACE) {
+       if ((m->stop > 0xffff) || (m->start & 3) ||
+           ((m->stop & 3) != 3))
+           return -EINVAL;
+       map += 2;
+    } else {
+       u_short bcr;
+       if ((m->start & 0x0fff) || ((m->stop & 0x0fff) != 0x0fff))
+           return -EINVAL;
+       pci_readw(s->bus, s->devfn, CB_BRIDGE_CONTROL, &bcr);
+       bcr &= ~CB_BCR_PREFETCH(map);
+       bcr |= (m->flags & MAP_PREFETCH) ? CB_BCR_PREFETCH(map) : 0;
+       pci_writew(s->bus, s->devfn, CB_BRIDGE_CONTROL, bcr);
+    }
+    if (m->flags & MAP_ACTIVE) {
+       pci_writel(s->bus, s->devfn, CB_MEM_BASE(map), m->start);
+       pci_writel(s->bus, s->devfn, CB_MEM_LIMIT(map), m->stop);
+    } else {
+       pci_writel(s->bus, s->devfn, CB_IO_BASE(map), 0);
+       pci_writel(s->bus, s->devfn, CB_IO_LIMIT(map), 0);
+    }
+    return 0;
+}
+
+#endif /* CONFIG_CARDBUS */
+
+/*======================================================================
+
+    Routines for accessing socket information and register dumps via
+    /proc/bus/pccard/...
+    
+======================================================================*/
+
+#ifdef CONFIG_PROC_FS
+
+static int proc_read_info(char *buf, char **start, off_t pos,
+                         int count, int *eof, void *data)
+{
+    socket_info_t *s = data;
+    char *p = buf;
+    p += sprintf(p, "type:     %s\npsock:    %d\n",
+                pcic[s->type].name, s->psock);
+#ifdef CONFIG_PCI
+    if (s->flags & (IS_PCI|IS_CARDBUS))
+       p += sprintf(p, "bus:      %02x\ndevfn:    %02x.%1x\n",
+                    s->bus, PCI_SLOT(s->devfn), PCI_FUNC(s->devfn));
+    if (s->flags & IS_CARDBUS)
+       p += sprintf(p, "cardbus:  %02x\n", s->cap.cardbus);
+#endif
+    return (p - buf);
+}
+
+static int proc_read_exca(char *buf, char **start, off_t pos,
+                         int count, int *eof, void *data)
+{
+    u_short sock = (socket_info_t *)data - socket;
+    char *p = buf;
+    int i, top;
+    
+#ifdef CONFIG_ISA
+    u_long flags = 0;
+    if (!(socket[sock].flags & IS_CARDBUS))
+       spin_lock_irqsave(&isa_lock, flags);
+#endif
+    top = 0x40;
+    if (socket[sock].flags & IS_CARDBUS)
+       top = (socket[sock].flags & IS_CIRRUS) ? 0x140 : 0x50;
+    for (i = 0; i < top; i += 4) {
+       if (i == 0x50) {
+           p += sprintf(p, "\n");
+           i = 0x100;
+       }
+       p += sprintf(p, "%02x %02x %02x %02x%s",
+                    i365_get(sock,i), i365_get(sock,i+1),
+                    i365_get(sock,i+2), i365_get(sock,i+3),
+                    ((i % 16) == 12) ? "\n" : " ");
+    }
+#ifdef CONFIG_ISA
+    if (!(socket[sock].flags & IS_CARDBUS))
+       spin_unlock_irqrestore(&isa_lock, flags);
+#endif
+    return (p - buf);
+}
+
+
+#ifdef CONFIG_PCI
+static int proc_read_pci(char *buf, char **start, off_t pos,
+                        int count, int *eof, void *data)
+{
+    socket_info_t *s = data;
+    u_char bus = s->bus, devfn = s->devfn;
+    char *p = buf;
+    u_int a, b, c, d;
+    int i;
+    
+    for (i = 0; i < 0xc0; i += 0x10) {
+       pci_readl(bus, devfn, i, &a);
+       pci_readl(bus, devfn, i+4, &b);
+       pci_readl(bus, devfn, i+8, &c);
+       pci_readl(bus, devfn, i+12, &d);
+       p += sprintf(p, "%08x %08x %08x %08x\n", a, b, c, d);
+    }
+    return (p - buf);
+}
+#endif
+
+#ifdef CONFIG_CARDBUS
+static int proc_read_cardbus(char *buf, char **start, off_t pos,
+                            int count, int *eof, void *data)
+{
+    u_short sock = (socket_info_t *)data - socket;
+    int len;
+    
+    len = sprintf(buf, "%08x %08x %08x %08x %08x %08x\n",
+                 cb_readl(sock,0), cb_readl(sock,4),
+                 cb_readl(sock,8), cb_readl(sock,12),
+                 cb_readl(sock,16), cb_readl(sock,32));
+    return len;
+}
+#endif
+
+static void pcic_proc_setup(u_short sock, struct proc_dir_entry *base)
+{
+    socket_info_t *s = &socket[sock];
+    struct proc_dir_entry *ent;
+    ent = create_proc_entry("info", 0, base);
+    ent->read_proc = proc_read_info;
+    ent->data = s;
+    ent = create_proc_entry("exca", 0, base);
+    ent->read_proc = proc_read_exca;
+    ent->data = s;
+#ifdef CONFIG_PCI
+    if (s->flags & (IS_PCI|IS_CARDBUS)) {
+       ent = create_proc_entry("pci", 0, base);
+       ent->read_proc = proc_read_pci;
+       ent->data = s;
+    }
+#endif
+#ifdef CONFIG_CARDBUS
+    if (s->flags & IS_CARDBUS) {
+       ent = create_proc_entry("cardbus", 0, base);
+       ent->read_proc = proc_read_cardbus;
+       ent->data = s;
+    }
+#endif
+    s->proc = base;
+}
+
+static void pcic_proc_remove(u_short sock)
+{
+    struct proc_dir_entry *base = socket[sock].proc;
+    if (base == NULL) return;
+    remove_proc_entry("info", base);
+    remove_proc_entry("exca", base);
+#ifdef CONFIG_PCI
+    if (socket[sock].flags & (IS_PCI|IS_CARDBUS))
+       remove_proc_entry("pci", base);
+#endif
+#ifdef CONFIG_CARDBUS
+    if (socket[sock].flags & IS_CARDBUS)
+       remove_proc_entry("cardbus", base);
+#endif
+}
+
+#endif /* CONFIG_PROC_FS */
+
+/*====================================================================*/
+
+typedef int (*subfn_t)(u_short, void *);
+
+static subfn_t pcic_service_table[] = {
+    (subfn_t)&pcic_register_callback,
+    (subfn_t)&pcic_inquire_socket,
+    (subfn_t)&i365_get_status,
+    (subfn_t)&i365_get_socket,
+    (subfn_t)&i365_set_socket,
+    (subfn_t)&i365_get_io_map,
+    (subfn_t)&i365_set_io_map,
+    (subfn_t)&i365_get_mem_map,
+    (subfn_t)&i365_set_mem_map,
+#ifdef CONFIG_CARDBUS
+    (subfn_t)&cb_get_bridge,
+    (subfn_t)&cb_set_bridge,
+#else
+    NULL, NULL,
+#endif
+#ifdef CONFIG_PROC_FS
+    (subfn_t)&pcic_proc_setup
+#endif
+};
+
+#define NFUNC (sizeof(pcic_service_table)/sizeof(subfn_t))
+
+static int pcic_service(u_int sock, u_int cmd, void *arg)
+{
+    subfn_t fn;
+
+    DEBUG(2, ("pcic_ioctl(%d, %d, 0x%p)\n", sock, cmd, arg));
+
+    if (cmd >= NFUNC)
+       return -EINVAL;
+
+    if (socket[sock].flags & IS_ALIVE) {
+       if (cmd == SS_GetStatus)
+           *(u_int *)arg = 0;
+       return -EINVAL;
+    }
+    
+    fn = pcic_service_table[cmd];
+#ifdef CONFIG_CARDBUS
+    if ((socket[sock].flags & IS_CARDBUS) &&
+       (cb_readl(sock, CB_SOCKET_STATE) & CB_SS_32BIT)) {
+       if (cmd == SS_GetStatus)
+           fn = (subfn_t)&cb_get_status;
+       else if (cmd == SS_GetSocket)
+           fn = (subfn_t)&cb_get_socket;
+       else if (cmd == SS_SetSocket)
+           fn = (subfn_t)&cb_set_socket;
+    }
+#endif
+
+#ifdef CONFIG_ISA
+    if (!(socket[sock].flags & IS_CARDBUS)) {
+       int ret;
+       u_long flags;
+       spin_lock_irqsave(&isa_lock, flags);
+       ret = (fn == NULL) ? -EINVAL : fn(sock, arg);
+       spin_unlock_irqrestore(&isa_lock, flags);
+       return ret;
+    }
+#endif
+    return (fn == NULL) ? -EINVAL : fn(sock, arg);
+} /* pcic_service */
+
+/*====================================================================*/
+
+int pcmcia_i82365_init(void)
+{
+    servinfo_t serv;
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+       printk(KERN_NOTICE "i82365: Card Services release "
+              "does not match!\n");
+       return -1;
+    }
+    return pcic_init();
+}
+
+#ifdef MODULE
+
+int init_module(void)
+{
+       return pcmcia_i82365_init();
+}
+
+void cleanup_module(void)
+{
+    pcic_finish();
+}
+
+#endif
+
+/*====================================================================*/
+
diff --git a/drivers/pcmcia/i82365.h b/drivers/pcmcia/i82365.h
new file mode 100644 (file)
index 0000000..ac3ba4e
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * i82365.h 1.14 1999/08/28 04:01:47
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_I82365_H
+#define _LINUX_I82365_H
+
+/* register definitions for the Intel 82365SL PCMCIA controller */
+
+/* Offsets for PCIC registers */
+#define I365_IDENT     0x00    /* Identification and revision */
+#define I365_STATUS    0x01    /* Interface status */
+#define I365_POWER     0x02    /* Power and RESETDRV control */
+#define I365_INTCTL    0x03    /* Interrupt and general control */
+#define I365_CSC       0x04    /* Card status change */
+#define I365_CSCINT    0x05    /* Card status change interrupt control */
+#define I365_ADDRWIN   0x06    /* Address window enable */
+#define I365_IOCTL     0x07    /* I/O control */
+#define I365_GENCTL    0x16    /* Card detect and general control */
+#define I365_GBLCTL    0x1E    /* Global control register */
+
+/* Offsets for I/O and memory window registers */
+#define I365_IO(map)   (0x08+((map)<<2))
+#define I365_MEM(map)  (0x10+((map)<<3))
+#define I365_W_START   0
+#define I365_W_STOP    2
+#define I365_W_OFF     4
+
+/* Flags for I365_STATUS */
+#define I365_CS_BVD1   0x01
+#define I365_CS_STSCHG 0x01
+#define I365_CS_BVD2   0x02
+#define I365_CS_SPKR   0x02
+#define I365_CS_DETECT 0x0C
+#define I365_CS_WRPROT 0x10
+#define I365_CS_READY  0x20    /* Inverted */
+#define I365_CS_POWERON        0x40
+#define I365_CS_GPI    0x80
+
+/* Flags for I365_POWER */
+#define I365_PWR_OFF   0x00    /* Turn off the socket */
+#define I365_PWR_OUT   0x80    /* Output enable */
+#define I365_PWR_NORESET 0x40  /* Disable RESETDRV on resume */
+#define I365_PWR_AUTO  0x20    /* Auto pwr switch enable */
+#define I365_VCC_MASK  0x18    /* Mask for turning off Vcc */
+/* There are different layouts for B-step and DF-step chips: the B
+   step has independent Vpp1/Vpp2 control, and the DF step has only
+   Vpp1 control, plus 3V control */
+#define I365_VCC_5V    0x10    /* Vcc = 5.0v */
+#define I365_VCC_3V    0x18    /* Vcc = 3.3v */
+#define I365_VPP2_MASK 0x0c    /* Mask for turning off Vpp2 */
+#define I365_VPP2_5V   0x04    /* Vpp2 = 5.0v */
+#define I365_VPP2_12V  0x08    /* Vpp2 = 12.0v */
+#define I365_VPP1_MASK 0x03    /* Mask for turning off Vpp1 */
+#define I365_VPP1_5V   0x01    /* Vpp2 = 5.0v */
+#define I365_VPP1_12V  0x02    /* Vpp2 = 12.0v */
+
+/* Flags for I365_INTCTL */
+#define I365_RING_ENA  0x80
+#define I365_PC_RESET  0x40
+#define I365_PC_IOCARD 0x20
+#define I365_INTR_ENA  0x10
+#define I365_IRQ_MASK  0x0F
+
+/* Flags for I365_CSC and I365_CSCINT*/
+#define I365_CSC_BVD1  0x01
+#define I365_CSC_STSCHG        0x01
+#define I365_CSC_BVD2  0x02
+#define I365_CSC_READY 0x04
+#define I365_CSC_DETECT        0x08
+#define I365_CSC_ANY   0x0F
+#define I365_CSC_GPI   0x10
+
+/* Flags for I365_ADDRWIN */
+#define I365_ENA_IO(map)       (0x40 << (map))
+#define I365_ENA_MEM(map)      (0x01 << (map))
+
+/* Flags for I365_IOCTL */
+#define I365_IOCTL_MASK(map)   (0x0F << (map<<2))
+#define I365_IOCTL_WAIT(map)   (0x08 << (map<<2))
+#define I365_IOCTL_0WS(map)    (0x04 << (map<<2))
+#define I365_IOCTL_IOCS16(map) (0x02 << (map<<2))
+#define I365_IOCTL_16BIT(map)  (0x01 << (map<<2))
+
+/* Flags for I365_GENCTL */
+#define I365_CTL_16DELAY       0x01
+#define I365_CTL_RESET         0x02
+#define I365_CTL_GPI_ENA       0x04
+#define I365_CTL_GPI_CTL       0x08
+#define I365_CTL_RESUME                0x10
+#define I365_CTL_SW_IRQ                0x20
+
+/* Flags for I365_GBLCTL */
+#define I365_GBL_PWRDOWN       0x01
+#define I365_GBL_CSC_LEV       0x02
+#define I365_GBL_WRBACK                0x04
+#define I365_GBL_IRQ_0_LEV     0x08
+#define I365_GBL_IRQ_1_LEV     0x10
+
+/* Flags for memory window registers */
+#define I365_MEM_16BIT 0x8000  /* In memory start high byte */
+#define I365_MEM_0WS   0x4000
+#define I365_MEM_WS1   0x8000  /* In memory stop high byte */
+#define I365_MEM_WS0   0x4000
+#define I365_MEM_WRPROT        0x8000  /* In offset high byte */
+#define I365_MEM_REG   0x4000
+
+#define I365_REG(slot, reg)    (((slot) << 6) + reg)
+
+#endif /* _LINUX_I82365_H */
diff --git a/drivers/pcmcia/o2micro.h b/drivers/pcmcia/o2micro.h
new file mode 100644 (file)
index 0000000..8052a71
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * o2micro.h $Revision: 1.9 $ $Date: 1999/08/28 04:01:47 $
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_O2MICRO_H
+#define _LINUX_O2MICRO_H
+
+#ifndef PCI_VENDOR_ID_O2
+#define PCI_VENDOR_ID_O2               0x1217
+#endif
+#ifndef PCI_DEVICE_ID_O2_6729
+#define PCI_DEVICE_ID_O2_6729          0x6729
+#endif
+#ifndef PCI_DEVICE_ID_O2_6730
+#define PCI_DEVICE_ID_O2_6730          0x673a
+#endif
+#ifndef PCI_DEVICE_ID_O2_6832
+#define PCI_DEVICE_ID_O2_6832          0x6832
+#endif
+#ifndef PCI_DEVICE_ID_O2_6836
+#define PCI_DEVICE_ID_O2_6836          0x6836
+#endif
+
+#define O2_MODE_A              0x38
+#define O2_MODE_A_2            0x26    /* For 6833B, 6860C */
+#define  O2_MODE_A_CD_PULSE    0x04
+#define  O2_MODE_A_SUSP_EDGE   0x08
+#define  O2_MODE_A_HOST_SUSP   0x10
+#define  O2_MODE_A_PWRCHIP     0x60
+#define  O2_MODE_A_QUIET       0x80
+
+#define O2_MODE_B              0x39
+#define O2_MODE_B_2            0x2e    /* For 6833B, 6860C */
+#define  O2_MODE_B_IDENT       0x03
+#define  O2_MODE_B_ID_BSTEP    0x00
+#define  O2_MODE_B_ID_CSTEP    0x01
+#define  O2_MODE_B_ID_O2       0x02
+#define  O2_MODE_B_VS1         0x04
+#define  O2_MODE_B_VS2         0x08
+#define  O2_MODE_B_IRQ15_RI    0x80
+
+#define O2_MODE_C              0x3a
+#define  O2_MODE_C_DREQ_MASK   0x03
+#define  O2_MODE_C_DREQ_INPACK 0x01
+#define  O2_MODE_C_DREQ_WP     0x02
+#define  O2_MODE_C_DREQ_BVD2   0x03
+#define  O2_MODE_C_ZVIDEO      0x08
+
+#define O2_MODE_D              0x3b
+#define  O2_MODE_D_IRQ_MODE    0x03
+#define  O2_MODE_D_SKT_ACTV    0x20
+#define  O2_MODE_D_PCI_FIFO    0x40    /* for OZ6729, OZ6730 */
+#define  O2_MODE_D_W97_IRQ     0x40    /* for OZ6832 */
+#define  O2_MODE_D_ISA_IRQ     0x80
+
+#define O2_MHPG_DMA            0x3c
+#define  O2_MHPG_CHANNEL       0x07
+#define  O2_MHPG_CINT_ENA      0x08
+#define  O2_MHPG_CSC_ENA       0x10
+
+#define O2_FIFO_ENA            0x3d
+#define  O2_FIFO_ZVIDEO_3      0x08
+#define  O2_FIFO_PCI_FIFO      0x10
+#define  O2_FIFO_POSTWR                0x40
+#define  O2_FIFO_BUFFER                0x80
+
+#define O2_MODE_E              0x3e
+#define  O2_MODE_E_MHPG_DMA    0x01
+#define  O2_MODE_E_SPKR_OUT    0x02
+#define  O2_MODE_E_LED_OUT     0x08
+#define  O2_MODE_E_SKTA_ACTV   0x10
+
+#endif /* _LINUX_O2MICRO_H */
diff --git a/drivers/pcmcia/ricoh.h b/drivers/pcmcia/ricoh.h
new file mode 100644 (file)
index 0000000..c6fceac
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * ricoh.h 1.8 1999/08/28 04:01:47
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_RICOH_H
+#define _LINUX_RICOH_H
+
+#define RF5C_MODE_CTL          0x1f    /* Mode control */
+#define RF5C_PWR_CTL           0x2f    /* Mixed voltage control */
+#define RF5C_CHIP_ID           0x3a    /* Chip identification */
+#define RF5C_MODE_CTL_3                0x3b    /* Mode control 3 */
+
+/* I/O window address offset */
+#define RF5C_IO_OFF(w)         (0x36+((w)<<1))
+
+/* Flags for RF5C_MODE_CTL */
+#define RF5C_MODE_ATA          0x01    /* ATA mode */
+#define RF5C_MODE_LED_ENA      0x02    /* IRQ 12 is LED */
+#define RF5C_MODE_CA21         0x04
+#define RF5C_MODE_CA22         0x08
+#define RF5C_MODE_CA23         0x10
+#define RF5C_MODE_CA24         0x20
+#define RF5C_MODE_CA25         0x40
+#define RF5C_MODE_3STATE_BIT7  0x80
+
+/* Flags for RF5C_PWR_CTL */
+#define RF5C_PWR_VCC_3V                0x01
+#define RF5C_PWR_IREQ_HIGH     0x02
+#define RF5C_PWR_INPACK_ENA    0x04
+#define RF5C_PWR_5V_DET                0x08
+#define RF5C_PWR_TC_SEL                0x10    /* Terminal Count: irq 11 or 15 */
+#define RF5C_PWR_DREQ_LOW      0x20
+#define RF5C_PWR_DREQ_OFF      0x00    /* DREQ steering control */
+#define RF5C_PWR_DREQ_INPACK   0x40
+#define RF5C_PWR_DREQ_SPKR     0x80
+#define RF5C_PWR_DREQ_IOIS16   0xc0
+
+/* Values for RF5C_CHIP_ID */
+#define RF5C_CHIP_RF5C296      0x32
+#define RF5C_CHIP_RF5C396      0xb2
+
+/* Flags for RF5C_MODE_CTL_3 */
+#define RF5C_MCTL3_DISABLE     0x01    /* Disable PCMCIA interface */
+#define RF5C_MCTL3_DMA_ENA     0x02
+
+/* Register definitions for Ricoh PCI-to-CardBus bridges */
+
+#ifndef PCI_VENDOR_ID_RICOH
+#define PCI_VENDOR_ID_RICOH            0x1180
+#endif
+#ifndef PCI_DEVICE_ID_RICOH_RL5C465
+#define PCI_DEVICE_ID_RICOH_RL5C465    0x0465
+#endif
+#ifndef PCI_DEVICE_ID_RICOH_RL5C466
+#define PCI_DEVICE_ID_RICOH_RL5C466    0x0466
+#endif
+#ifndef PCI_DEVICE_ID_RICOH_RL5C475
+#define PCI_DEVICE_ID_RICOH_RL5C475    0x0475
+#endif
+#ifndef PCI_DEVICE_ID_RICOH_RL5C476
+#define PCI_DEVICE_ID_RICOH_RL5C476    0x0476
+#endif
+#ifndef PCI_DEVICE_ID_RICOH_RL5C478
+#define PCI_DEVICE_ID_RICOH_RL5C478    0x0478
+#endif
+
+/* Extra bits in CB_BRIDGE_CONTROL */
+#define RL5C46X_BCR_3E0_ENA            0x0800
+#define RL5C46X_BCR_3E2_ENA            0x1000
+
+/* Misc Control Register */
+#define RL5C4XX_MISC                   0x0082  /* 16 bit */
+#define  RL5C4XX_MISC_HW_SUSPEND_ENA   0x0002
+#define  RL5C4XX_MISC_VCCEN_POL                0x0100
+#define  RL5C4XX_MISC_VPPEN_POL                0x0200
+#define  RL5C46X_MISC_SUSPEND          0x0001
+#define  RL5C46X_MISC_PWR_SAVE_2       0x0004
+#define  RL5C46X_MISC_IFACE_BUSY       0x0008
+#define  RL5C46X_MISC_B_LOCK           0x0010
+#define  RL5C46X_MISC_A_LOCK           0x0020
+#define  RL5C46X_MISC_PCI_LOCK         0x0040
+#define  RL5C47X_MISC_IFACE_BUSY       0x0004
+#define  RL5C47X_MISC_PCI_INT_MASK     0x0018
+#define  RL5C47X_MISC_PCI_INT_DIS      0x0020
+#define  RL5C47X_MISC_SUBSYS_WR                0x0040
+#define  RL5C47X_MISC_SRIRQ_ENA                0x0080
+#define  RL5C47X_MISC_5V_DISABLE       0x0400
+#define  RL5C47X_MISC_LED_POL          0x0800
+
+/* 16-bit Interface Control Register */
+#define RL5C4XX_16BIT_CTL              0x0084  /* 16 bit */
+#define  RL5C4XX_16CTL_IO_TIMING       0x0100
+#define  RL5C4XX_16CTL_MEM_TIMING      0x0200
+#define  RL5C46X_16CTL_LEVEL_1         0x0010
+#define  RL5C46X_16CTL_LEVEL_2         0x0020
+
+/* 16-bit IO and memory timing registers */
+#define RL5C4XX_16BIT_IO_0             0x0088  /* 16 bit */
+#define RL5C4XX_16BIT_MEM_0            0x0088  /* 16 bit */
+#define  RL5C4XX_SETUP_MASK            0x0007
+#define  RL5C4XX_SETUP_SHIFT           0
+#define  RL5C4XX_CMD_MASK              0x01f0
+#define  RL5C4XX_CMD_SHIFT             4
+#define  RL5C4XX_HOLD_MASK             0x1c00
+#define  RL5C4XX_HOLD_SHIFT            10
+
+#endif /* _LINUX_RICOH_H */
diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c
new file mode 100644 (file)
index 0000000..f44b33b
--- /dev/null
@@ -0,0 +1,802 @@
+/*======================================================================
+
+    Resource management routines
+
+    rsrc_mgr.c 1.69 1999/08/28 04:01:46
+
+    The contents of this file are subject to the Mozilla Public
+    License Version 1.1 (the "License"); you may not use this file
+    except in compliance with the License. You may obtain a copy of
+    the License at http://www.mozilla.org/MPL/
+
+    Software distributed under the License is distributed on an "AS
+    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+    implied. See the License for the specific language governing
+    rights and limitations under the License.
+
+    The initial developer of the original code is David A. Hinds
+    <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+
+    Alternatively, the contents of this file may be used under the
+    terms of the GNU Public License version 2 (the "GPL"), in which
+    case the provisions of the GPL are applicable instead of the
+    above.  If you wish to allow the use of your version of this file
+    only under the terms of the GPL and not to allow others to use
+    your version of this file under the MPL, indicate your decision
+    by deleting the provisions above and replace them with the notice
+    and other provisions required by the GPL.  If you do not delete
+    the provisions above, a recipient may use your version of this
+    file under either the MPL or the GPL.
+    
+======================================================================*/
+
+#define __NO_VERSION__
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <linux/timer.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/bulkmem.h>
+#include <pcmcia/cistpl.h>
+#include "cs_internal.h"
+#include "rsrc_mgr.h"
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* Should we probe resources for conflicts? */
+static int probe_mem = 1;
+MODULE_PARM(probe_mem, "i");
+#ifdef CONFIG_ISA
+static int probe_io = 1;
+static int mem_limit = 0x10000;
+MODULE_PARM(probe_io, "i");
+MODULE_PARM(mem_limit, "i");
+#endif
+
+/*======================================================================
+
+    The resource_map_t structures are used to track what resources are
+    available for allocation for PC Card devices.
+
+======================================================================*/
+
+typedef struct resource_map_t {
+    u_long                     base, num;
+    struct resource_map_t      *next;
+} resource_map_t;
+
+/* Memory resource database */
+static resource_map_t mem_db = { 0, 0, &mem_db };
+
+/* IO port resource database */
+static resource_map_t io_db = { 0, 0, &io_db };
+
+#ifdef CONFIG_ISA
+
+typedef struct irq_info_t {
+    u_int                      Attributes;
+    int                                time_share, dyn_share;
+    struct socket_info_t       *Socket;
+} irq_info_t;
+
+/* Table of IRQ assignments */
+static irq_info_t irq_table[NR_IRQS] = { { 0, 0, 0 }, /* etc */ };
+
+#endif
+
+static spinlock_t rsrc_lock = SPIN_LOCK_UNLOCKED;
+
+/*======================================================================
+
+    Linux resource management extensions
+    
+======================================================================*/
+
+typedef struct resource_entry_t {
+    u_long                     base, num;
+    char                       *name;
+    struct resource_entry_t    *next;
+} resource_entry_t;
+
+/* Ordered linked lists of allocated IO and memory blocks */
+static resource_entry_t io_list = { 0, 0, NULL, NULL };
+#ifndef HAVE_MEMRESERVE
+static resource_entry_t mem_list = { 0, 0, NULL, NULL };
+#endif
+
+static resource_entry_t *find_gap(resource_entry_t *root,
+                                 resource_entry_t *entry)
+{
+    resource_entry_t *p;
+    
+    if (entry->base > entry->base+entry->num-1)
+       return NULL;
+    for (p = root; ; p = p->next) {
+       if ((p != root) && (p->base+p->num-1 >= entry->base)) {
+           p = NULL;
+           break;
+       }
+       if ((p->next == NULL) ||
+           (p->next->base > entry->base+entry->num-1))
+           break;
+    }
+    return p;
+}
+
+static int register_my_resource(resource_entry_t *list,
+                               u_long base, u_long num, char *name)
+{
+    u_long flags;
+    resource_entry_t *p, *entry;
+
+    entry = kmalloc(sizeof(resource_entry_t), GFP_ATOMIC);
+    entry->base = base;
+    entry->num = num;
+    entry->name = name;
+
+    spin_lock_irqsave(&rsrc_lock, flags);
+    p = find_gap(list, entry);
+    if (p == NULL) {
+       spin_unlock_irqrestore(&rsrc_lock, flags);
+       kfree(entry);
+       return -EBUSY;
+    }
+    entry->next = p->next;
+    p->next = entry;
+    spin_unlock_irqrestore(&rsrc_lock, flags);
+    return 0;
+}
+
+static void release_my_resource(resource_entry_t *list,
+                               u_long base, u_long num)
+{
+    u_long flags;
+    resource_entry_t *p, *q;
+
+    spin_lock_irqsave(&rsrc_lock, flags);
+    for (p = list; ; p = q) {
+       q = p->next;
+       if (q == NULL) break;
+       if ((q->base == base) && (q->num == num)) {
+           p->next = q->next;
+           kfree(q);
+           spin_unlock_irqrestore(&rsrc_lock, flags);
+           return;
+       }
+    }
+    spin_unlock_irqrestore(&rsrc_lock, flags);
+    return;
+}
+
+static int check_my_resource(resource_entry_t *list,
+                            u_long base, u_long num)
+{
+    if (register_my_resource(list, base, num, NULL) != 0)
+       return -EBUSY;
+    release_my_resource(list, base, num);
+    return 0;
+}
+
+int check_io_region(u_long base, u_long num)
+{
+    return check_my_resource(&io_list, base, num);
+}
+void request_io_region(u_long base, u_long num, char *name)
+{
+    register_my_resource(&io_list, base, num, name);
+}
+void release_io_region(u_long base, u_long num)
+{
+    release_my_resource(&io_list, base, num);
+}
+#ifdef CONFIG_PROC_FS
+int proc_read_io(char *buf, char **start, off_t pos,
+                int count, int *eof, void *data)
+{
+    resource_entry_t *r;
+    u_long flags;
+    char *p = buf;
+    
+    spin_lock_irqsave(&rsrc_lock, flags);
+    for (r = io_list.next; r; r = r->next)
+       p += sprintf(p, "%04lx-%04lx : %s\n", r->base,
+                    r->base+r->num-1, r->name);
+    spin_unlock_irqrestore(&rsrc_lock, flags);
+    return (p - buf);
+}
+#endif
+
+
+/*======================================================================
+
+    These manage the internal databases of available resources.
+    
+======================================================================*/
+
+static int add_interval(resource_map_t *map, u_long base, u_long num)
+{
+    resource_map_t *p, *q;
+
+    for (p = map; ; p = p->next) {
+       if ((p != map) && (p->base+p->num-1 >= base))
+           return -1;
+       if ((p->next == map) || (p->next->base > base+num-1))
+           break;
+    }
+    q = kmalloc(sizeof(resource_map_t), GFP_KERNEL);
+    q->base = base; q->num = num;
+    q->next = p->next; p->next = q;
+    return 0;
+} /* add_interval */
+
+/*====================================================================*/
+
+static int sub_interval(resource_map_t *map, u_long base, u_long num)
+{
+    resource_map_t *p, *q;
+
+    for (p = map; ; p = q) {
+       q = p->next;
+       if (q == map)
+           break;
+       if ((q->base+q->num > base) && (base+num > q->base)) {
+           if (q->base >= base) {
+               if (q->base+q->num <= base+num) {
+                   /* Delete whole block */
+                   p->next = q->next;
+                   kfree(q);
+                   /* don't advance the pointer yet */
+                   q = p;
+               } else {
+                   /* Cut off bit from the front */
+                   q->num = q->base + q->num - base - num;
+                   q->base = base + num;
+               }
+           } else if (q->base+q->num <= base+num) {
+               /* Cut off bit from the end */
+               q->num = base - q->base;
+           } else {
+               /* Split the block into two pieces */
+               p = kmalloc(sizeof(resource_map_t), GFP_KERNEL);
+               p->base = base+num;
+               p->num = q->base+q->num - p->base;
+               q->num = base - q->base;
+               p->next = q->next ; q->next = p;
+           }
+       }
+    }
+    return 0;
+} /* sub_interval */
+
+/*======================================================================
+
+    These routines examine a region of IO or memory addresses to
+    determine what ranges might be genuinely available.
+    
+======================================================================*/
+
+#ifdef CONFIG_ISA
+static void do_io_probe(ioaddr_t base, ioaddr_t num)
+{
+    
+    ioaddr_t i, j, bad, any;
+    u_char *b, hole, most;
+    
+    printk(KERN_INFO "cs: IO port probe 0x%04x-0x%04x:",
+          base, base+num-1);
+    
+    /* First, what does a floating port look like? */
+    b = kmalloc(256, GFP_KERNEL);
+    memset(b, 0, 256);
+    for (i = base, most = 0; i < base+num; i += 8) {
+       if (check_region(i, 8) || check_io_region(i, 8))
+           continue;
+       hole = inb(i);
+       for (j = 1; j < 8; j++)
+           if (inb(i+j) != hole) break;
+       if ((j == 8) && (++b[hole] > b[most]))
+           most = hole;
+       if (b[most] == 127) break;
+    }
+    kfree(b);
+
+    bad = any = 0;
+    for (i = base; i < base+num; i += 8) {
+       if (check_region(i, 8) || check_io_region(i, 8))
+           continue;
+       for (j = 0; j < 8; j++)
+           if (inb(i+j) != most) break;
+       if (j < 8) {
+           if (!any)
+               printk(" excluding");
+           if (!bad)
+               bad = any = i;
+       } else {
+           if (bad) {
+               sub_interval(&io_db, bad, i-bad);
+               printk(" %#04x-%#04x", bad, i-1);
+               bad = 0;
+           }
+       }
+    }
+    if (bad) {
+       if ((num > 16) && (bad == base) && (i == base+num)) {
+           printk(" nothing: probe failed.\n");
+           return;
+       } else {
+           sub_interval(&io_db, bad, i-bad);
+           printk(" %#04x-%#04x", bad, i-1);
+       }
+    }
+    
+    printk(any ? "\n" : " clean.\n");
+}
+#endif
+
+/*======================================================================
+
+    The memory probe.  If the memory list includes a 64K-aligned block
+    below 1MB, we probe in 64K chunks, and as soon as we accumulate at
+    least mem_limit free space, we quit.
+    
+======================================================================*/
+
+static int do_mem_probe(u_long base, u_long num,
+                       int (*is_valid)(u_long), int (*do_cksum)(u_long))
+{
+    u_long i, j, bad, fail, step;
+
+    printk(KERN_INFO "cs: memory probe 0x%06lx-0x%06lx:",
+          base, base+num-1);
+
+    bad = fail = 0;
+    step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff);
+    for (i = base; i < base+num; i = j + step) {
+       if (!fail) {    
+           for (j = i; j < base+num; j += step)
+               if ((check_mem_region(j, step) == 0) && is_valid(j))
+                   break;
+           fail = ((i == base) && (j == base+num));
+       }
+       if (fail) {
+           for (j = i; j < base+num; j += 2*step)
+               if ((check_mem_region(j, 2*step) == 0) &&
+                   do_cksum(j) && do_cksum(j+step))
+                   break;
+       }
+       if (i != j) {
+           if (!bad) printk(" excluding");
+           printk(" %#05lx-%#05lx", i, j-1);
+           sub_interval(&mem_db, i, j-i);
+           bad += j-i;
+       }
+    }
+    printk(bad ? "\n" : " clean.\n");
+
+    return (num - bad);
+}
+
+#ifdef CONFIG_ISA
+
+static u_long inv_probe(int (*is_valid)(u_long),
+                       int (*do_cksum)(u_long),
+                       resource_map_t *m)
+{
+    u_long ok;
+    if (m == &mem_db)
+       return 0;
+    ok = inv_probe(is_valid, do_cksum, m->next);
+    if (ok) {
+       if (m->base >= 0x100000)
+           sub_interval(&mem_db, m->base, m->num);
+       return ok;
+    }
+    if (m->base < 0x100000)
+       return 0;
+    return do_mem_probe(m->base, m->num, is_valid, do_cksum);
+}
+
+void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long),
+                 int force_low)
+{
+    resource_map_t *m, *n;
+    static u_char order[] = { 0xd0, 0xe0, 0xc0, 0xf0 };
+    static int hi = 0, lo = 0;
+    u_long b, i, ok = 0;
+    
+    if (!probe_mem) return;
+    /* We do up to four passes through the list */
+    if (!force_low) {
+       if (hi++ || (inv_probe(is_valid, do_cksum, mem_db.next) > 0))
+           return;
+       printk(KERN_NOTICE "cs: warning: no high memory space "
+              "available!\n");
+    }
+    if (lo++) return;
+    for (m = mem_db.next; m != &mem_db; m = n) {
+       n = m->next;
+       /* Only probe < 1 MB */
+       if (m->base >= 0x100000) continue;
+       if ((m->base | m->num) & 0xffff) {
+           ok += do_mem_probe(m->base, m->num, is_valid, do_cksum);
+           continue;
+       }
+       /* Special probe for 64K-aligned block */
+       for (i = 0; i < 4; i++) {
+           b = order[i] << 12;
+           if ((b >= m->base) && (b+0x10000 <= m->base+m->num)) {
+               if (ok >= mem_limit)
+                   sub_interval(&mem_db, b, 0x10000);
+               else
+                   ok += do_mem_probe(b, 0x10000, is_valid, do_cksum);
+           }
+       }
+    }
+}
+
+#else /* CONFIG_ISA */
+
+void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long),
+                 int force_low)
+{
+    resource_map_t *m;
+    static int done = 0;
+    
+    if (!probe_mem || done++)
+       return;
+    for (m = mem_db.next; m != &mem_db; m = m->next)
+       if (do_mem_probe(m->base, m->num, is_valid, do_cksum))
+           return;
+}
+
+#endif /* CONFIG_ISA */
+
+/*======================================================================
+
+    These find ranges of I/O ports or memory addresses that are not
+    currently allocated by other devices.
+    
+======================================================================*/
+
+int find_io_region(ioaddr_t *base, ioaddr_t num, char *name)
+{
+    ioaddr_t align;
+    resource_map_t *m;
+    
+    if (*base != 0) {
+       for (m = io_db.next; m != &io_db; m = m->next) {
+           if ((*base >= m->base) && (*base+num <= m->base+m->num)) {
+               if (check_region(*base, num) ||
+                   check_io_region(*base, num)) {
+                   return -1;
+               } else {
+                   request_region(*base, num, name);
+                   return 0;
+               }
+           }
+       }
+       return -1;
+    }
+    
+    for (align = 1; align < num; align *= 2) ;
+
+    for (m = io_db.next; m != &io_db; m = m->next) {
+       for (*base = (m->base + align - 1) & (~(align-1));
+            *base+align <= m->base + m->num;
+            *base += align)
+           if ((check_region(*base, num) == 0) &&
+               (check_io_region(*base, num) == 0)) {
+               request_region(*base, num, name);
+               return 0;
+           }
+    }
+    return -1;
+} /* find_io_region */
+
+int find_mem_region(u_long *base, u_long num, char *name,
+                   u_long align, int force_low)
+{
+    resource_map_t *m;
+
+    if (*base != 0) {
+       for (m = mem_db.next; m != &mem_db; m = m->next) {
+           if ((*base >= m->base) && (*base+num <= m->base+m->num))
+               if (check_mem_region(*base, num) == 0) {
+                   request_mem_region(*base, num, name);
+                   return 0;
+               }
+       }
+       return -1;
+    }
+    
+    while (1) {
+       for (m = mem_db.next; m != &mem_db; m = m->next) {
+           /* first pass >1MB, second pass <1MB */
+           if ((force_low != 0) ^ (m->base < 0x100000)) continue;
+           for (*base = (m->base + align - 1) & (~(align-1));
+                *base+num <= m->base+m->num; *base += align)
+               if (check_mem_region(*base, num) == 0) {
+                   request_mem_region(*base, num, name);
+                   return 0;
+               }
+       }
+       if (force_low) break;
+       force_low++;
+    }
+    return -1;
+} /* find_mem_region */
+
+/*======================================================================
+
+    This checks to see if an interrupt is available, with support
+    for interrupt sharing.  We don't support reserving interrupts
+    yet.  If the interrupt is available, we allocate it.
+    
+======================================================================*/
+
+#ifdef CONFIG_ISA
+
+static void fake_irq(int i, void *d, struct pt_regs *r) { }
+static inline int check_irq(int irq)
+{
+    if (request_irq(irq, fake_irq, 0, "bogus", NULL) != 0)
+       return -1;
+    free_irq(irq, NULL);
+    return 0;
+}
+
+int try_irq(u_int Attributes, int irq, int specific)
+{
+    irq_info_t *info = &irq_table[irq];
+    if (info->Attributes & RES_ALLOCATED) {
+       switch (Attributes & IRQ_TYPE) {
+       case IRQ_TYPE_EXCLUSIVE:
+           return CS_IN_USE;
+       case IRQ_TYPE_TIME:
+           if ((info->Attributes & RES_IRQ_TYPE)
+               != RES_IRQ_TYPE_TIME)
+               return CS_IN_USE;
+           if (Attributes & IRQ_FIRST_SHARED)
+               return CS_BAD_ATTRIBUTE;
+           info->Attributes |= RES_IRQ_TYPE_TIME | RES_ALLOCATED;
+           info->time_share++;
+           break;
+       case IRQ_TYPE_DYNAMIC_SHARING:
+           if ((info->Attributes & RES_IRQ_TYPE)
+               != RES_IRQ_TYPE_DYNAMIC)
+               return CS_IN_USE;
+           if (Attributes & IRQ_FIRST_SHARED)
+               return CS_BAD_ATTRIBUTE;
+           info->Attributes |= RES_IRQ_TYPE_DYNAMIC | RES_ALLOCATED;
+           info->dyn_share++;
+           break;
+       }
+    } else {
+       if ((info->Attributes & RES_RESERVED) && !specific)
+           return CS_IN_USE;
+       if (check_irq(irq) != 0)
+           return CS_IN_USE;
+       switch (Attributes & IRQ_TYPE) {
+       case IRQ_TYPE_EXCLUSIVE:
+           info->Attributes |= RES_ALLOCATED;
+           break;
+       case IRQ_TYPE_TIME:
+           if (!(Attributes & IRQ_FIRST_SHARED))
+               return CS_BAD_ATTRIBUTE;
+           info->Attributes |= RES_IRQ_TYPE_TIME | RES_ALLOCATED;
+           info->time_share = 1;
+           break;
+       case IRQ_TYPE_DYNAMIC_SHARING:
+           if (!(Attributes & IRQ_FIRST_SHARED))
+               return CS_BAD_ATTRIBUTE;
+           info->Attributes |= RES_IRQ_TYPE_DYNAMIC | RES_ALLOCATED;
+           info->dyn_share = 1;
+           break;
+       }
+    }
+    return 0;
+} /* try_irq */
+
+#endif
+
+/*====================================================================*/
+
+#ifdef CONFIG_ISA
+
+void undo_irq(u_int Attributes, int irq)
+{
+    irq_info_t *info;
+
+    info = &irq_table[irq];
+    switch (Attributes & IRQ_TYPE) {
+    case IRQ_TYPE_EXCLUSIVE:
+       info->Attributes &= RES_RESERVED;
+       break;
+    case IRQ_TYPE_TIME:
+       info->time_share--;
+       if (info->time_share == 0)
+           info->Attributes &= RES_RESERVED;
+       break;
+    case IRQ_TYPE_DYNAMIC_SHARING:
+       info->dyn_share--;
+       if (info->dyn_share == 0)
+           info->Attributes &= RES_RESERVED;
+       break;
+    }
+}
+
+#endif
+
+/*======================================================================
+
+    The various adjust_* calls form the external interface to the
+    resource database.
+    
+======================================================================*/
+
+static int adjust_memory(adjust_t *adj)
+{
+    u_long base, num;
+    int i;
+
+    base = adj->resource.memory.Base;
+    num = adj->resource.memory.Size;
+    if ((num == 0) || (base+num-1 < base))
+       return CS_BAD_SIZE;
+
+    switch (adj->Action) {
+    case ADD_MANAGED_RESOURCE:
+       if (add_interval(&mem_db, base, num) != 0)
+           return CS_IN_USE;
+       break;
+    case REMOVE_MANAGED_RESOURCE:
+       sub_interval(&mem_db, base, num);
+       for (i = 0; i < sockets; i++) {
+           release_cis_mem(socket_table[i]);
+#ifdef CONFIG_CARDBUS
+           cb_release_cis_mem(socket_table[i]);
+#endif
+       }
+       break;
+    default:
+       return CS_UNSUPPORTED_FUNCTION;
+       break;
+    }
+    
+    return CS_SUCCESS;
+} /* adjust_mem */
+
+/*====================================================================*/
+
+static int adjust_io(adjust_t *adj)
+{
+    int base, num;
+    
+    base = adj->resource.io.BasePort;
+    num = adj->resource.io.NumPorts;
+    if ((base < 0) || (base > 0xffff))
+       return CS_BAD_BASE;
+    if ((num <= 0) || (base+num > 0x10000) || (base+num <= base))
+       return CS_BAD_SIZE;
+
+    switch (adj->Action) {
+    case ADD_MANAGED_RESOURCE:
+       if (add_interval(&io_db, base, num) != 0)
+           return CS_IN_USE;
+#ifdef CONFIG_ISA
+       if (probe_io)
+           do_io_probe(base, num);
+#endif
+       break;
+    case REMOVE_MANAGED_RESOURCE:
+       sub_interval(&io_db, base, num);
+       break;
+    default:
+       return CS_UNSUPPORTED_FUNCTION;
+       break;
+    }
+
+    return CS_SUCCESS;
+} /* adjust_io */
+
+/*====================================================================*/
+
+static int adjust_irq(adjust_t *adj)
+{
+#ifdef CONFIG_ISA
+    int irq;
+    irq_info_t *info;
+    
+    irq = adj->resource.irq.IRQ;
+    if ((irq < 0) || (irq > 15))
+       return CS_BAD_IRQ;
+    info = &irq_table[irq];
+    
+    switch (adj->Action) {
+    case ADD_MANAGED_RESOURCE:
+       if (info->Attributes & RES_REMOVED)
+           info->Attributes &= ~(RES_REMOVED|RES_ALLOCATED);
+       else
+           if (adj->Attributes & RES_ALLOCATED)
+               return CS_IN_USE;
+       if (adj->Attributes & RES_RESERVED)
+           info->Attributes |= RES_RESERVED;
+       else
+           info->Attributes &= ~RES_RESERVED;
+       break;
+    case REMOVE_MANAGED_RESOURCE:
+       if (info->Attributes & RES_REMOVED)
+           return 0;
+       if (info->Attributes & RES_ALLOCATED)
+           return CS_IN_USE;
+       info->Attributes |= RES_ALLOCATED|RES_REMOVED;
+       info->Attributes &= ~RES_RESERVED;
+       break;
+    default:
+       return CS_UNSUPPORTED_FUNCTION;
+       break;
+    }
+#endif
+    return CS_SUCCESS;
+} /* adjust_irq */
+
+/*====================================================================*/
+
+int adjust_resource_info(client_handle_t handle, adjust_t *adj)
+{
+    if (CHECK_HANDLE(handle))
+       return CS_BAD_HANDLE;
+    
+    switch (adj->Resource) {
+    case RES_MEMORY_RANGE:
+       return adjust_memory(adj);
+       break;
+    case RES_IO_RANGE:
+       return adjust_io(adj);
+       break;
+    case RES_IRQ:
+       return adjust_irq(adj);
+       break;
+    }
+    return CS_UNSUPPORTED_FUNCTION;
+} /* adjust_resource_info */
+
+/*====================================================================*/
+
+void release_resource_db(void)
+{
+    resource_map_t *p, *q;
+    resource_entry_t *u, *v;
+    
+    for (p = mem_db.next; p != &mem_db; p = q) {
+       q = p->next;
+       kfree(p);
+    }
+    for (p = io_db.next; p != &io_db; p = q) {
+       q = p->next;
+       kfree(p);
+    }
+    for (u = io_list.next; u; u = v) {
+       v = u->next;
+       kfree(u);
+    }
+#ifndef HAVE_MEMRESERVE
+    for (u = mem_list.next; u; u = v) {
+       v = u->next;
+       kfree(u);
+    }
+#endif
+}
diff --git a/drivers/pcmcia/rsrc_mgr.h b/drivers/pcmcia/rsrc_mgr.h
new file mode 100644 (file)
index 0000000..3b7f12e
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * rsrc_mgr.h 1.18 1999/08/28 04:01:47
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _RSRC_MGR_H
+#define _RSRC_MGR_H
+
+#ifdef __BEOS__
+int check_resource(int type, u_long base, u_long num);
+int register_resource(int type, u_long base, u_long num);
+int release_resource(int type, u_long base, u_long num);
+#endif
+
+#endif /* _RSRC_MGR_H */
diff --git a/drivers/pcmcia/smc34c90.h b/drivers/pcmcia/smc34c90.h
new file mode 100644 (file)
index 0000000..8ac3854
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * smc34c90.h 1.6 1999/08/28 04:01:47
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_SMC34C90_H
+#define _LINUX_SMC34C90_H
+
+#ifndef PCI_VENDOR_ID_SMC
+#define PCI_VENDOR_ID_SMC              0x10b3
+#endif
+
+#ifndef PCI_DEVICE_ID_SMC_34C90
+#define PCI_DEVICE_ID_SMC_34C90                0xb106
+#endif
+
+/* Register definitions for SMC 34C90 PCI-to-CardBus bridge */
+
+/* EEPROM Information Register */
+#define SMC34C90_EEINFO                        0x0088
+#define SMC34C90_EEINFO_ONE_SOCKET     0x0001
+#define SMC34C90_EEINFO_5V_ONLY                0x0002
+#define SMC34C90_EEINFO_ISA_IRQ                0x0004
+#define SMC34C90_EEINFO_ZV_PORT                0x0008
+#define SMC34C90_EEINFO_RING           0x0010
+#define SMC34C90_EEINFO_LED            0x0020
+
+#endif /* _LINUX_SMC34C90_H */
diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c
new file mode 100644 (file)
index 0000000..f5eb565
--- /dev/null
@@ -0,0 +1,979 @@
+/*======================================================================
+
+    Device driver for Databook TCIC-2 PCMCIA controller
+
+    tcic.c 1.104 1999/08/28 04:01:46
+
+    The contents of this file are subject to the Mozilla Public
+    License Version 1.1 (the "License"); you may not use this file
+    except in compliance with the License. You may obtain a copy of
+    the License at http://www.mozilla.org/MPL/
+
+    Software distributed under the License is distributed on an "AS
+    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+    implied. See the License for the specific language governing
+    rights and limitations under the License.
+
+    The initial developer of the original code is David A. Hinds
+    <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+
+    Alternatively, the contents of this file may be used under the
+    terms of the GNU Public License version 2 (the "GPL"), in which
+    case the provisions of the GPL are applicable instead of the
+    above.  If you wish to allow the use of your version of this file
+    only under the terms of the GPL and not to allow others to use
+    your version of this file under the MPL, indicate your decision
+    by deleting the provisions above and replace them with the notice
+    and other provisions required by the GPL.  If you do not delete
+    the provisions above, a recipient may use your version of this
+    file under either the MPL or the GPL.
+    
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/string.h>
+
+#include <asm/io.h>
+#include <asm/bitops.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/ss.h>
+#include "tcic.h"
+
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+static const char *version =
+"tcic.c 1.104 1999/08/28 04:01:46 (David Hinds)";
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* The base port address of the TCIC-2 chip */
+static int tcic_base = TCIC_BASE;
+
+/* Specify a socket number to ignore */
+static int ignore = -1;
+
+/* Probe for safe interrupts? */
+static int do_scan = 1;
+
+/* Bit map of interrupts to choose from */
+static u_int irq_mask = 0xffff;
+static int irq_list[16] = { -1 };
+
+/* The card status change interrupt -- 0 means autoselect */
+static int cs_irq = 0;
+
+/* Poll status interval -- 0 means default to interrupt */
+static int poll_interval = 0;
+
+/* Delay for card status double-checking */
+static int poll_quick = HZ/20;
+
+/* CCLK external clock time, in nanoseconds.  70 ns = 14.31818 MHz */
+static int cycle_time = 70;
+
+MODULE_PARM(tcic_base, "i");
+MODULE_PARM(ignore, "i");
+MODULE_PARM(do_scan, "i");
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-16i");
+MODULE_PARM(cs_irq, "i");
+MODULE_PARM(poll_interval, "i");
+MODULE_PARM(poll_quick, "i");
+MODULE_PARM(cycle_time, "i");
+
+/*====================================================================*/
+
+static void tcic_interrupt(int irq, void *dev, struct pt_regs *regs);
+static void tcic_timer(u_long data);
+static int tcic_service(u_int sock, u_int cmd, void *arg);
+
+typedef struct socket_info_t {
+    u_short    psock;
+    void       (*handler)(void *info, u_int events);
+    void       *info;
+    u_char     last_sstat;
+    u_char     id;
+} socket_info_t;
+
+static struct timer_list poll_timer;
+static int tcic_timer_pending = 0;
+
+static int sockets;
+static socket_info_t socket_table[2];
+
+static socket_cap_t tcic_cap = {
+    /* only 16-bit cards, memory windows must be size-aligned */
+    SS_CAP_PCCARD | SS_CAP_MEM_ALIGN,
+    0x4cf8,            /* irq 14, 11, 10, 7, 6, 5, 4, 3 */
+    0x1000,            /* 4K minimum window size */
+    0, 0               /* No PCI or CardBus support */
+};
+
+/*====================================================================*/
+
+/* Trick when selecting interrupts: the TCIC sktirq pin is supposed
+   to map to irq 11, but is coded as 0 or 1 in the irq registers. */
+#define TCIC_IRQ(x) ((x) ? (((x) == 11) ? 1 : (x)) : 15)
+
+#ifdef PCMCIA_DEBUG_X
+static u_char tcic_getb(u_char reg)
+{
+    u_char val = inb(tcic_base+reg);
+    printk(KERN_DEBUG "tcic_getb(%#x) = %#x\n", tcic_base+reg, val);
+    return val;
+}
+
+static u_short tcic_getw(u_char reg)
+{
+    u_short val = inw(tcic_base+reg);
+    printk(KERN_DEBUG "tcic_getw(%#x) = %#x\n", tcic_base+reg, val);
+    return val;
+}
+
+static void tcic_setb(u_char reg, u_char data)
+{
+    printk(KERN_DEBUG "tcic_setb(%#x, %#x)\n", tcic_base+reg, data);
+    outb(data, tcic_base+reg);
+}
+
+static void tcic_setw(u_char reg, u_short data)
+{
+    printk(KERN_DEBUG "tcic_setw(%#x, %#x)\n", tcic_base+reg, data);
+    outw(data, tcic_base+reg);
+}
+#else
+#define tcic_getb(reg) inb(tcic_base+reg)
+#define tcic_getw(reg) inw(tcic_base+reg)
+#define tcic_setb(reg, data) outb(data, tcic_base+reg)
+#define tcic_setw(reg, data) outw(data, tcic_base+reg)
+#endif
+
+static void tcic_setl(u_char reg, u_int data)
+{
+#ifdef PCMCIA_DEBUG_X
+    printk(KERN_DEBUG "tcic_setl(%#x, %#lx)\n", tcic_base+reg, data);
+#endif
+    outw(data & 0xffff, tcic_base+reg);
+    outw(data >> 16, tcic_base+reg+2);
+}
+
+static u_char tcic_aux_getb(u_short reg)
+{
+    u_char mode = (tcic_getb(TCIC_MODE) & TCIC_MODE_PGMMASK) | reg;
+    tcic_setb(TCIC_MODE, mode);
+    return tcic_getb(TCIC_AUX);
+}
+
+static void tcic_aux_setb(u_short reg, u_char data)
+{
+    u_char mode = (tcic_getb(TCIC_MODE) & TCIC_MODE_PGMMASK) | reg;
+    tcic_setb(TCIC_MODE, mode);
+    tcic_setb(TCIC_AUX, data);
+}
+
+static u_short tcic_aux_getw(u_short reg)
+{
+    u_char mode = (tcic_getb(TCIC_MODE) & TCIC_MODE_PGMMASK) | reg;
+    tcic_setb(TCIC_MODE, mode);
+    return tcic_getw(TCIC_AUX);
+}
+
+static void tcic_aux_setw(u_short reg, u_short data)
+{
+    u_char mode = (tcic_getb(TCIC_MODE) & TCIC_MODE_PGMMASK) | reg;
+    tcic_setb(TCIC_MODE, mode);
+    tcic_setw(TCIC_AUX, data);
+}
+
+/*====================================================================*/
+
+/* Time conversion functions */
+
+static int to_cycles(int ns)
+{
+    if (ns < 14)
+       return 0;
+    else
+       return 2*(ns-14)/cycle_time;
+}
+
+static int to_ns(int cycles)
+{
+    return (cycles*cycle_time)/2 + 14;
+}
+
+/*====================================================================*/
+
+static volatile u_int irq_hits;
+
+static void irq_count(int irq, void *dev, struct pt_regs *regs)
+{
+    irq_hits++;
+}
+
+static u_int try_irq(int irq)
+{
+    u_short cfg;
+
+    irq_hits = 0;
+    if (request_irq(irq, irq_count, 0, "irq scan", NULL) != 0)
+       return -1;
+    mdelay(10);
+    if (irq_hits) {
+       free_irq(irq, NULL);
+       return -1;
+    }
+
+    /* Generate one interrupt */
+    cfg = TCIC_SYSCFG_AUTOBUSY | 0x0a00;
+    tcic_aux_setw(TCIC_AUX_SYSCFG, cfg | TCIC_IRQ(irq));
+    tcic_setb(TCIC_IENA, TCIC_IENA_ERR | TCIC_IENA_CFG_HIGH);
+    tcic_setb(TCIC_ICSR, TCIC_ICSR_ERR | TCIC_ICSR_JAM);
+
+    udelay(1000);
+    free_irq(irq, NULL);
+
+    /* Turn off interrupts */
+    tcic_setb(TCIC_IENA, TCIC_IENA_CFG_OFF);
+    while (tcic_getb(TCIC_ICSR))
+       tcic_setb(TCIC_ICSR, TCIC_ICSR_JAM);
+    tcic_aux_setw(TCIC_AUX_SYSCFG, cfg);
+    
+    return (irq_hits != 1);
+}
+
+static u_int irq_scan(u_int mask0)
+{
+    u_int mask1;
+    int i;
+
+#ifdef __alpha__
+#define PIC 0x4d0
+    /* Don't probe level-triggered interrupts -- reserved for PCI */
+    int level_mask = inb_p(PIC) | (inb_p(PIC+1) << 8);
+    if (level_mask)
+       mask0 &= ~level_mask;
+#endif
+
+    mask1 = 0;
+    if (do_scan) {
+       for (i = 0; i < 16; i++)
+           if ((mask0 & (1 << i)) && (try_irq(i) == 0))
+               mask1 |= (1 << i);
+       for (i = 0; i < 16; i++)
+           if ((mask1 & (1 << i)) && (try_irq(i) != 0)) {
+               mask1 ^= (1 << i);
+           }
+    }
+    
+    if (mask1) {
+       printk("scanned");
+    } else {
+       /* Fallback: just find interrupts that aren't in use */
+       for (i = 0; i < 16; i++)
+           if ((mask0 & (1 << i)) &&
+               (request_irq(i, irq_count, 0, "x", NULL) == 0)) {
+               mask1 |= (1 << i);
+               free_irq(i, NULL);
+           }
+       printk("default");
+    }
+    
+    printk(") = ");
+    for (i = 0; i < 16; i++)
+       if (mask1 & (1<<i))
+           printk("%s%d", ((mask1 & ((1<<i)-1)) ? "," : ""), i);
+    printk(" ");
+    
+    return mask1;
+}
+
+/*======================================================================
+
+    See if a card is present, powered up, in IO mode, and already
+    bound to a (non-PCMCIA) Linux driver.
+
+    We make an exception for cards that look like serial devices.
+    
+======================================================================*/
+
+static int is_active(int s)
+{
+    u_short scf1, ioctl, base, num;
+    u_char pwr, sstat;
+    u_int addr;
+    
+    tcic_setl(TCIC_ADDR, (s << TCIC_ADDR_SS_SHFT)
+             | TCIC_ADDR_INDREG | TCIC_SCF1(s));
+    scf1 = tcic_getw(TCIC_DATA);
+    pwr = tcic_getb(TCIC_PWR);
+    sstat = tcic_getb(TCIC_SSTAT);
+    addr = TCIC_IWIN(s, 0);
+    tcic_setw(TCIC_ADDR, addr + TCIC_IBASE_X);
+    base = tcic_getw(TCIC_DATA);
+    tcic_setw(TCIC_ADDR, addr + TCIC_ICTL_X);
+    ioctl = tcic_getw(TCIC_DATA);
+
+    if (ioctl & TCIC_ICTL_TINY)
+       num = 1;
+    else {
+       num = (base ^ (base-1));
+       base = base & (base-1);
+    }
+
+    if ((sstat & TCIC_SSTAT_CD) && (pwr & TCIC_PWR_VCC(s)) &&
+       (scf1 & TCIC_SCF1_IOSTS) && (ioctl & TCIC_ICTL_ENA) &&
+       (check_region(base, num) != 0) && ((base & 0xfeef) != 0x02e8))
+       return 1;
+    else
+       return 0;
+}
+
+/*======================================================================
+
+    This returns the revision code for the specified socket.
+    
+======================================================================*/
+
+static int get_tcic_id(void)
+{
+    u_short id;
+    
+    tcic_aux_setw(TCIC_AUX_TEST, TCIC_TEST_DIAG);
+    id = tcic_aux_getw(TCIC_AUX_ILOCK);
+    id = (id & TCIC_ILOCKTEST_ID_MASK) >> TCIC_ILOCKTEST_ID_SH;
+    tcic_aux_setw(TCIC_AUX_TEST, 0);
+    return id;
+}
+
+/*====================================================================*/
+
+int tcic_init(void)
+{
+    int i, sock;
+    u_int mask, scan;
+
+    DEBUG(0, "%s\n", version);
+    
+    printk(KERN_INFO "Databook TCIC-2 PCMCIA probe: ");
+    sock = 0;
+
+    if (check_region(tcic_base, 16) == 0) {
+       tcic_setw(TCIC_ADDR, 0);
+       if (tcic_getw(TCIC_ADDR) == 0) {
+           tcic_setw(TCIC_ADDR, 0xc3a5);
+           if (tcic_getw(TCIC_ADDR) == 0xc3a5) sock = 2;
+       }
+       if (sock == 0) {
+           /* See if resetting the controller does any good */
+           tcic_setb(TCIC_SCTRL, TCIC_SCTRL_RESET);
+           tcic_setb(TCIC_SCTRL, 0);
+           tcic_setw(TCIC_ADDR, 0);
+           if (tcic_getw(TCIC_ADDR) == 0) {
+               tcic_setw(TCIC_ADDR, 0xc3a5);
+               if (tcic_getw(TCIC_ADDR) == 0xc3a5) sock = 2;
+           }
+       }
+    } else
+       printk("could not allocate ports, ");
+
+    if (sock == 0) {
+       printk("not found.\n");
+       return -ENODEV;
+    }
+
+    request_region(tcic_base, 16, "tcic-2");
+
+    sockets = 0;
+    for (i = 0; i < sock; i++) {
+       if ((i == ignore) || is_active(i)) continue;
+       socket_table[sockets].psock = i;
+       socket_table[sockets].handler = NULL;
+       socket_table[sockets].info = NULL;
+       socket_table[sockets].id = get_tcic_id();
+       sockets++;
+    }
+
+    switch (socket_table[0].id) {
+    case TCIC_ID_DB86082:
+       printk("DB86082"); break;
+    case TCIC_ID_DB86082A:
+       printk("DB86082A"); break;
+    case TCIC_ID_DB86084:
+       printk("DB86084"); break;
+    case TCIC_ID_DB86084A:
+       printk("DB86084A"); break;
+    case TCIC_ID_DB86072:
+       printk("DB86072"); break;
+    case TCIC_ID_DB86184:
+       printk("DB86184"); break;
+    case TCIC_ID_DB86082B:
+       printk("DB86082B"); break;
+    default:
+       printk("Unknown ID 0x%02x", socket_table[0].id);
+    }
+    
+    /* Set up polling */
+    poll_timer.function = &tcic_timer;
+    poll_timer.data = 0;
+    poll_timer.prev = poll_timer.next = NULL;
+
+    /* Build interrupt mask */
+    printk(", %d sockets\n" KERN_INFO "  irq list (", sockets);
+    if (irq_list[0] == -1)
+       mask = irq_mask;
+    else
+       for (i = mask = 0; i < 16; i++)
+           mask |= (1<<irq_list[i]);
+    mask &= tcic_cap.irq_mask;
+
+    /* Scan interrupts */
+    mask = irq_scan(mask);
+    tcic_cap.irq_mask = mask;
+    
+    /* Check for only two interrupts available */
+    scan = (mask & (mask-1));
+    if (((scan & (scan-1)) == 0) && (poll_interval == 0))
+       poll_interval = HZ;
+    
+    if (poll_interval == 0) {
+       /* Avoid irq 12 unless it is explicitly requested */
+       u_int cs_mask = mask & ((cs_irq) ? (1<<cs_irq) : ~(1<<12));
+       for (i = 15; i > 0; i--)
+           if ((cs_mask & (1 << i)) &&
+               (request_irq(i, tcic_interrupt, 0, "tcic", NULL) == 0))
+               break;
+       cs_irq = i;
+       if (cs_irq == 0) poll_interval = HZ;
+    }
+    
+    if (tcic_cap.irq_mask & (1 << 11))
+       printk("sktirq is irq 11, ");
+    if (cs_irq != 0)
+       printk("status change on irq %d\n", cs_irq);
+    else
+       printk("polled status, interval = %d ms\n",
+              poll_interval * 1000 / HZ);
+    
+    for (i = 0; i < sockets; i++) {
+       tcic_setw(TCIC_ADDR+2, socket_table[i].psock << TCIC_SS_SHFT);
+       socket_table[i].last_sstat = tcic_getb(TCIC_SSTAT);
+    }
+    
+    /* jump start interrupt handler, if needed */
+    tcic_interrupt(0, NULL, NULL);
+
+    if (register_ss_entry(sockets, &tcic_service) != 0) {
+       printk(KERN_NOTICE "tcic: register_ss_entry() failed\n");
+       release_region(tcic_base, 16);
+       if (cs_irq != 0)
+           free_irq(cs_irq, NULL);
+       return -ENODEV;
+    }
+
+    return 0;
+    
+} /* tcic_init */
+
+/*====================================================================*/
+
+static void tcic_finish(void)
+{
+    u_long flags;
+    unregister_ss_entry(&tcic_service);
+    save_flags(flags);
+    cli();
+    if (cs_irq != 0) {
+       tcic_aux_setw(TCIC_AUX_SYSCFG, TCIC_SYSCFG_AUTOBUSY|0x0a00);
+       free_irq(cs_irq, NULL);
+    }
+    if (tcic_timer_pending)
+       del_timer(&poll_timer);
+    restore_flags(flags);
+    release_region(tcic_base, 16);
+} /* tcic_finish */
+
+/*====================================================================*/
+
+static void tcic_interrupt(int irq, void *dev, struct pt_regs *regs)
+{
+    int i, quick = 0;
+    u_char latch, sstat;
+    u_short psock;
+    u_int events;
+    static volatile int active = 0;
+
+    if (active) {
+       printk(KERN_NOTICE "tcic: reentered interrupt handler!\n");
+       return;
+    } else
+       active = 1;
+
+    DEBUG(2, "tcic: tcic_interrupt()\n");
+    
+    for (i = 0; i < sockets; i++) {
+       psock = socket_table[i].psock;
+       tcic_setl(TCIC_ADDR, (psock << TCIC_ADDR_SS_SHFT)
+                 | TCIC_ADDR_INDREG | TCIC_SCF1(psock));
+       sstat = tcic_getb(TCIC_SSTAT);
+       latch = sstat ^ socket_table[psock].last_sstat;
+       socket_table[i].last_sstat = sstat;
+       if (tcic_getb(TCIC_ICSR) & TCIC_ICSR_CDCHG) {
+           tcic_setb(TCIC_ICSR, TCIC_ICSR_CLEAR);
+           quick = 1;
+       }
+       if ((latch == 0) || (socket_table[psock].handler == NULL))
+           continue;
+       events = (latch & TCIC_SSTAT_CD) ? SS_DETECT : 0;
+       events |= (latch & TCIC_SSTAT_WP) ? SS_WRPROT : 0;
+       if (tcic_getw(TCIC_DATA) & TCIC_SCF1_IOSTS) {
+           events |= (latch & TCIC_SSTAT_LBAT1) ? SS_STSCHG : 0;
+       } else {
+           events |= (latch & TCIC_SSTAT_RDY) ? SS_READY : 0;
+           events |= (latch & TCIC_SSTAT_LBAT1) ? SS_BATDEAD : 0;
+           events |= (latch & TCIC_SSTAT_LBAT2) ? SS_BATWARN : 0;
+       }
+       if (events)
+           socket_table[i].handler(socket_table[i].info, events);
+    }
+
+    /* Schedule next poll, if needed */
+    if (((cs_irq == 0) || quick) && (!tcic_timer_pending)) {
+       poll_timer.expires = jiffies + (quick ? poll_quick : poll_interval);
+       add_timer(&poll_timer);
+       tcic_timer_pending = 1;
+    }
+    active = 0;
+    
+    DEBUG(2, "tcic: interrupt done\n");
+    
+} /* tcic_interrupt */
+
+static void tcic_timer(u_long data)
+{
+    DEBUG(2, "tcic: tcic_timer()\n");
+    tcic_timer_pending = 0;
+    tcic_interrupt(0, NULL, NULL);
+} /* tcic_timer */
+
+/*====================================================================*/
+
+static int tcic_register_callback(u_short lsock, ss_callback_t *call)
+{
+    if (call == NULL) {
+       socket_table[lsock].handler = NULL;
+       MOD_DEC_USE_COUNT;
+    } else {
+       MOD_INC_USE_COUNT;
+       socket_table[lsock].handler = call->handler;
+       socket_table[lsock].info = call->info;
+    }
+    return 0;
+} /* tcic_register_callback */
+
+/*====================================================================*/
+
+static int tcic_get_status(u_short lsock, u_int *value)
+{
+    u_short psock = socket_table[lsock].psock;
+    u_char reg;
+
+    tcic_setl(TCIC_ADDR, (psock << TCIC_ADDR_SS_SHFT)
+             | TCIC_ADDR_INDREG | TCIC_SCF1(psock));
+    reg = tcic_getb(TCIC_SSTAT);
+    *value  = (reg & TCIC_SSTAT_CD) ? SS_DETECT : 0;
+    *value |= (reg & TCIC_SSTAT_WP) ? SS_WRPROT : 0;
+    if (tcic_getw(TCIC_DATA) & TCIC_SCF1_IOSTS) {
+       *value |= (reg & TCIC_SSTAT_LBAT1) ? SS_STSCHG : 0;
+    } else {
+       *value |= (reg & TCIC_SSTAT_RDY) ? SS_READY : 0;
+       *value |= (reg & TCIC_SSTAT_LBAT1) ? SS_BATDEAD : 0;
+       *value |= (reg & TCIC_SSTAT_LBAT2) ? SS_BATWARN : 0;
+    }
+    reg = tcic_getb(TCIC_PWR);
+    if (reg & (TCIC_PWR_VCC(psock)|TCIC_PWR_VPP(psock)))
+       *value |= SS_POWERON;
+    DEBUG(1, "tcic: GetStatus(%d) = %#2.2x\n", lsock, *value);
+    return 0;
+} /* tcic_get_status */
+  
+/*====================================================================*/
+
+static int tcic_inquire_socket(u_short lsock, socket_cap_t *cap)
+{
+    *cap = tcic_cap;
+    return 0;
+} /* tcic_inquire_socket */
+
+/*====================================================================*/
+
+static int tcic_get_socket(u_short lsock, socket_state_t *state)
+{
+    u_short psock = socket_table[lsock].psock;
+    u_char reg;
+    u_short scf1, scf2;
+    
+    tcic_setl(TCIC_ADDR, (psock << TCIC_ADDR_SS_SHFT)
+             | TCIC_ADDR_INDREG | TCIC_SCF1(psock));
+    scf1 = tcic_getw(TCIC_DATA);
+    state->flags = (scf1 & TCIC_SCF1_IOSTS) ? SS_IOCARD : 0;
+    state->flags |= (scf1 & TCIC_SCF1_DMA_MASK) ? SS_DMA_MODE : 0;
+    state->flags |= (scf1 & TCIC_SCF1_SPKR) ? SS_SPKR_ENA : 0;
+    if (tcic_getb(TCIC_SCTRL) & TCIC_SCTRL_ENA)
+       state->flags |= SS_OUTPUT_ENA;
+    state->io_irq = scf1 & TCIC_SCF1_IRQ_MASK;
+    if (state->io_irq == 1) state->io_irq = 11;
+
+    reg = tcic_getb(TCIC_PWR);
+    state->Vcc = state->Vpp = 0;
+    if (reg & TCIC_PWR_VCC(psock)) {
+       if (reg & TCIC_PWR_VPP(psock))
+           state->Vcc = 50;
+       else
+           state->Vcc = state->Vpp = 50;
+    } else {
+       if (reg & TCIC_PWR_VPP(psock)) {
+           state->Vcc = 50;
+           state->Vpp = 120;
+       }
+    }
+    reg = tcic_aux_getb(TCIC_AUX_ILOCK);
+    state->flags |= (reg & TCIC_ILOCK_CRESET) ? SS_RESET : 0;
+
+    /* Card status change interrupt mask */
+    tcic_setw(TCIC_ADDR, TCIC_SCF2(psock));
+    scf2 = tcic_getw(TCIC_DATA);
+    state->csc_mask = (scf2 & TCIC_SCF2_MCD) ? 0 : SS_DETECT;
+    if (state->flags & SS_IOCARD) {
+       state->csc_mask |= (scf2 & TCIC_SCF2_MLBAT1) ? 0 : SS_STSCHG;
+    } else {
+       state->csc_mask |= (scf2 & TCIC_SCF2_MLBAT1) ? 0 : SS_BATDEAD;
+       state->csc_mask |= (scf2 & TCIC_SCF2_MLBAT2) ? 0 : SS_BATWARN;
+       state->csc_mask |= (scf2 & TCIC_SCF2_MRDY) ? 0 : SS_READY;
+    }
+
+    DEBUG(1, "tcic: GetSocket(%d) = flags %#3.3x, Vcc %d, Vpp %d, "
+         "io_irq %d, csc_mask %#2.2x\n", lsock, state->flags,
+         state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
+    return 0;
+} /* tcic_get_socket */
+
+/*====================================================================*/
+
+static int tcic_set_socket(u_short lsock, socket_state_t *state)
+{
+    u_short psock = socket_table[lsock].psock;
+    u_char reg;
+    u_short scf1, scf2;
+
+    DEBUG(1, "tcic: SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, "
+         "io_irq %d, csc_mask %#2.2x)\n", lsock, state->flags,
+         state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
+    tcic_setw(TCIC_ADDR+2, (psock << TCIC_SS_SHFT) | TCIC_ADR2_INDREG);
+
+    reg = tcic_getb(TCIC_PWR);
+    reg &= ~(TCIC_PWR_VCC(psock) | TCIC_PWR_VPP(psock));
+
+    if (state->Vcc == 50) {
+       switch (state->Vpp) {
+       case 0:   reg |= TCIC_PWR_VCC(psock) | TCIC_PWR_VPP(psock); break;
+       case 50:  reg |= TCIC_PWR_VCC(psock); break;
+       case 120: reg |= TCIC_PWR_VPP(psock); break;
+       default:  return -EINVAL;
+       }
+    } else if (state->Vcc != 0)
+       return -EINVAL;
+
+    if (reg != tcic_getb(TCIC_PWR))
+       tcic_setb(TCIC_PWR, reg);
+
+    reg = TCIC_ILOCK_HOLD_CCLK | TCIC_ILOCK_CWAIT;
+    if (state->flags & SS_OUTPUT_ENA) {
+       tcic_setb(TCIC_SCTRL, TCIC_SCTRL_ENA);
+       reg |= TCIC_ILOCK_CRESENA;
+    } else
+       tcic_setb(TCIC_SCTRL, 0);
+    if (state->flags & SS_RESET)
+       reg |= TCIC_ILOCK_CRESET;
+    tcic_aux_setb(TCIC_AUX_ILOCK, reg);
+    
+    tcic_setw(TCIC_ADDR, TCIC_SCF1(psock));
+    scf1 = TCIC_SCF1_FINPACK;
+    scf1 |= TCIC_IRQ(state->io_irq);
+    if (state->flags & SS_IOCARD) {
+       scf1 |= TCIC_SCF1_IOSTS;
+       if (state->flags & SS_SPKR_ENA)
+           scf1 |= TCIC_SCF1_SPKR;
+       if (state->flags & SS_DMA_MODE)
+           scf1 |= TCIC_SCF1_DREQ2 << TCIC_SCF1_DMA_SHIFT;
+    }
+    tcic_setw(TCIC_DATA, scf1);
+
+    /* Some general setup stuff, and configure status interrupt */
+    reg = TCIC_WAIT_ASYNC | TCIC_WAIT_SENSE | to_cycles(250);
+    tcic_aux_setb(TCIC_AUX_WCTL, reg);
+    tcic_aux_setw(TCIC_AUX_SYSCFG, TCIC_SYSCFG_AUTOBUSY|0x0a00|
+                 TCIC_IRQ(cs_irq));
+    
+    /* Card status change interrupt mask */
+    tcic_setw(TCIC_ADDR, TCIC_SCF2(psock));
+    scf2 = TCIC_SCF2_MALL;
+    if (state->csc_mask & SS_DETECT) scf2 &= ~TCIC_SCF2_MCD;
+    if (state->flags & SS_IOCARD) {
+       if (state->csc_mask & SS_STSCHG) reg &= ~TCIC_SCF2_MLBAT1;
+    } else {
+       if (state->csc_mask & SS_BATDEAD) reg &= ~TCIC_SCF2_MLBAT1;
+       if (state->csc_mask & SS_BATWARN) reg &= ~TCIC_SCF2_MLBAT2;
+       if (state->csc_mask & SS_READY) reg &= ~TCIC_SCF2_MRDY;
+    }
+    tcic_setw(TCIC_DATA, scf2);
+    /* For the ISA bus, the irq should be active-high totem-pole */
+    tcic_setb(TCIC_IENA, TCIC_IENA_CDCHG | TCIC_IENA_CFG_HIGH);
+
+    return 0;
+} /* tcic_set_socket */
+  
+/*====================================================================*/
+
+static int tcic_get_io_map(u_short lsock, struct pccard_io_map *io)
+{
+    u_short psock = socket_table[lsock].psock;
+    u_short base, ioctl;
+    u_int addr;
+    
+    if (io->map > 1) return -EINVAL;
+    tcic_setw(TCIC_ADDR+2, TCIC_ADR2_INDREG | (psock << TCIC_SS_SHFT));
+    addr = TCIC_IWIN(psock, io->map);
+    tcic_setw(TCIC_ADDR, addr + TCIC_IBASE_X);
+    base = tcic_getw(TCIC_DATA);
+    tcic_setw(TCIC_ADDR, addr + TCIC_ICTL_X);
+    ioctl = tcic_getw(TCIC_DATA);
+
+    if (ioctl & TCIC_ICTL_TINY)
+       io->start = io->stop = base;
+    else {
+       io->start = base & (base-1);
+       io->stop = io->start + (base ^ (base-1));
+    }
+    io->speed = to_ns(ioctl & TCIC_ICTL_WSCNT_MASK);
+    io->flags  = (ioctl & TCIC_ICTL_ENA) ? MAP_ACTIVE : 0;
+    switch (ioctl & TCIC_ICTL_BW_MASK) {
+    case TCIC_ICTL_BW_DYN:
+       io->flags |= MAP_AUTOSZ; break;
+    case TCIC_ICTL_BW_16:
+       io->flags |= MAP_16BIT; break;
+    default:
+       break;
+    }
+    DEBUG(1, "tcic: GetIOMap(%d, %d) = %#2.2x, %d ns, "
+         "%#4.4x-%#4.4x\n", lsock, io->map, io->flags,
+         io->speed, io->start, io->stop);
+    return 0;
+} /* tcic_get_io_map */
+
+/*====================================================================*/
+
+static int tcic_set_io_map(u_short lsock, struct pccard_io_map *io)
+{
+    u_short psock = socket_table[lsock].psock;
+    u_int addr;
+    u_short base, len, ioctl;
+    
+    DEBUG(1, "tcic: SetIOMap(%d, %d, %#2.2x, %d ns, "
+         "%#4.4x-%#4.4x)\n", lsock, io->map, io->flags,
+         io->speed, io->start, io->stop);
+    if ((io->map > 1) || (io->start > 0xffff) || (io->stop > 0xffff) ||
+       (io->stop < io->start)) return -EINVAL;
+    tcic_setw(TCIC_ADDR+2, TCIC_ADR2_INDREG | (psock << TCIC_SS_SHFT));
+    addr = TCIC_IWIN(psock, io->map);
+
+    base = io->start; len = io->stop - io->start;
+    /* Check to see that len+1 is power of two, etc */
+    if ((len & (len+1)) || (base & len)) return -EINVAL;
+    base |= (len+1)>>1;
+    tcic_setw(TCIC_ADDR, addr + TCIC_IBASE_X);
+    tcic_setw(TCIC_DATA, base);
+    
+    ioctl  = (psock << TCIC_ICTL_SS_SHFT);
+    ioctl |= (len == 0) ? TCIC_ICTL_TINY : 0;
+    ioctl |= (io->flags & MAP_ACTIVE) ? TCIC_ICTL_ENA : 0;
+    ioctl |= to_cycles(io->speed) & TCIC_ICTL_WSCNT_MASK;
+    if (!(io->flags & MAP_AUTOSZ)) {
+       ioctl |= TCIC_ICTL_QUIET;
+       ioctl |= (io->flags & MAP_16BIT) ? TCIC_ICTL_BW_16 : TCIC_ICTL_BW_8;
+    }
+    tcic_setw(TCIC_ADDR, addr + TCIC_ICTL_X);
+    tcic_setw(TCIC_DATA, ioctl);
+    
+    return 0;
+} /* tcic_set_io_map */
+
+/*====================================================================*/
+
+static int tcic_get_mem_map(u_short lsock, struct pccard_mem_map *mem)
+{
+    u_short psock = socket_table[lsock].psock;
+    u_short addr, ctl;
+    u_long base, mmap;
+    
+    if (mem->map > 3) return -EINVAL;
+    tcic_setw(TCIC_ADDR+2, TCIC_ADR2_INDREG | (psock << TCIC_SS_SHFT));
+    addr = TCIC_MWIN(psock, mem->map);
+    
+    tcic_setw(TCIC_ADDR, addr + TCIC_MBASE_X);
+    base = tcic_getw(TCIC_DATA);
+    if (base & TCIC_MBASE_4K_BIT) {
+       mem->sys_start = base & TCIC_MBASE_HA_MASK;
+       mem->sys_stop = mem->sys_start;
+    } else {
+       base &= TCIC_MBASE_HA_MASK;
+       mem->sys_start = (base & (base-1));
+       mem->sys_stop = mem->sys_start + (base ^ (base-1));
+    }
+    mem->sys_start = mem->sys_start << TCIC_MBASE_HA_SHFT;
+    mem->sys_stop = (mem->sys_stop << TCIC_MBASE_HA_SHFT) + 0x0fff;
+    
+    tcic_setw(TCIC_ADDR, addr + TCIC_MMAP_X);
+    mmap = tcic_getw(TCIC_DATA);
+    mem->flags = (mmap & TCIC_MMAP_REG) ? MAP_ATTRIB : 0;
+    mmap &= TCIC_MMAP_CA_MASK;
+    mem->card_start = mem->sys_start + (mmap << TCIC_MMAP_CA_SHFT);
+    mem->card_start &= 0x3ffffff;
+    
+    tcic_setw(TCIC_ADDR, addr + TCIC_MCTL_X);
+    ctl = tcic_getw(TCIC_DATA);
+    mem->flags |= (ctl & TCIC_MCTL_ENA) ? MAP_ACTIVE : 0;
+    mem->flags |= (ctl & TCIC_MCTL_B8) ? 0 : MAP_16BIT;
+    mem->flags |= (ctl & TCIC_MCTL_WP) ? MAP_WRPROT : 0;
+    mem->speed = to_ns(ctl & TCIC_MCTL_WSCNT_MASK);
+    
+    DEBUG(1, "tcic: GetMemMap(%d, %d) = %#2.2x, %d ns, "
+         "%#5.5lx-%#5.5lx, %#5.5x\n", lsock, mem->map, mem->flags,
+         mem->speed, mem->sys_start, mem->sys_stop, mem->card_start);
+    return 0;
+} /* tcic_get_mem_map */
+
+/*====================================================================*/
+  
+static int tcic_set_mem_map(u_short lsock, struct pccard_mem_map *mem)
+{
+    u_short psock = socket_table[lsock].psock;
+    u_short addr, ctl;
+    u_long base, len, mmap;
+
+    DEBUG(1, "tcic: SetMemMap(%d, %d, %#2.2x, %d ns, "
+         "%#5.5lx-%#5.5lx, %#5.5x)\n", lsock, mem->map, mem->flags,
+         mem->speed, mem->sys_start, mem->sys_stop, mem->card_start);
+    if ((mem->map > 3) || (mem->card_start > 0x3ffffff) ||
+       (mem->sys_start > 0xffffff) || (mem->sys_stop > 0xffffff) ||
+       (mem->sys_start > mem->sys_stop) || (mem->speed > 1000))
+       return -EINVAL;
+    tcic_setw(TCIC_ADDR+2, TCIC_ADR2_INDREG | (psock << TCIC_SS_SHFT));
+    addr = TCIC_MWIN(psock, mem->map);
+
+    base = mem->sys_start; len = mem->sys_stop - mem->sys_start;
+    if ((len & (len+1)) || (base & len)) return -EINVAL;
+    if (len == 0x0fff)
+       base = (base >> TCIC_MBASE_HA_SHFT) | TCIC_MBASE_4K_BIT;
+    else
+       base = (base | (len+1)>>1) >> TCIC_MBASE_HA_SHFT;
+    tcic_setw(TCIC_ADDR, addr + TCIC_MBASE_X);
+    tcic_setw(TCIC_DATA, base);
+    
+    mmap = mem->card_start - mem->sys_start;
+    mmap = (mmap >> TCIC_MMAP_CA_SHFT) & TCIC_MMAP_CA_MASK;
+    if (mem->flags & MAP_ATTRIB) mmap |= TCIC_MMAP_REG;
+    tcic_setw(TCIC_ADDR, addr + TCIC_MMAP_X);
+    tcic_setw(TCIC_DATA, mmap);
+
+    ctl  = TCIC_MCTL_QUIET | (psock << TCIC_MCTL_SS_SHFT);
+    ctl |= to_cycles(mem->speed) & TCIC_MCTL_WSCNT_MASK;
+    ctl |= (mem->flags & MAP_16BIT) ? 0 : TCIC_MCTL_B8;
+    ctl |= (mem->flags & MAP_WRPROT) ? TCIC_MCTL_WP : 0;
+    ctl |= (mem->flags & MAP_ACTIVE) ? TCIC_MCTL_ENA : 0;
+    tcic_setw(TCIC_ADDR, addr + TCIC_MCTL_X);
+    tcic_setw(TCIC_DATA, ctl);
+    
+    return 0;
+} /* tcic_set_mem_map */
+
+/*====================================================================*/
+
+typedef int (*subfn_t)(u_short, void *);
+    
+static subfn_t service_table[] = {
+    (subfn_t)&tcic_register_callback,
+    (subfn_t)&tcic_inquire_socket,
+    (subfn_t)&tcic_get_status,
+    (subfn_t)&tcic_get_socket,
+    (subfn_t)&tcic_set_socket,
+    (subfn_t)&tcic_get_io_map,
+    (subfn_t)&tcic_set_io_map,
+    (subfn_t)&tcic_get_mem_map,
+    (subfn_t)&tcic_set_mem_map,
+};
+
+#define NFUNC (sizeof(service_table)/sizeof(subfn_t))
+
+static int tcic_service(u_int lsock, u_int cmd, void *arg)
+{
+    int err;
+
+    DEBUG(2, "tcic_service(%d, %d, 0x%p)\n", lsock, cmd, arg);
+
+    if (cmd < NFUNC)
+       err = service_table[cmd](lsock, arg);
+    else
+       err = -EINVAL;
+
+    return err;
+} /* tcic_service */
+
+/*====================================================================*/
+
+int pcmcia_tcic_init(void)
+{
+    servinfo_t serv;
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+       printk(KERN_NOTICE "tcic: Card Services release "
+              "does not match!\n");
+       return -1;
+    }
+    return tcic_init();
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+       return pcmcia_tcic_init();
+}
+
+void cleanup_module(void)
+{
+    tcic_finish();
+}
+#endif
diff --git a/drivers/pcmcia/tcic.h b/drivers/pcmcia/tcic.h
new file mode 100644 (file)
index 0000000..e33f795
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ * tcic.h 1.12 1999/08/28 04:01:47
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_TCIC_H
+#define _LINUX_TCIC_H
+
+#define TCIC_BASE              0x240
+
+/* offsets of registers from TCIC_BASE */
+#define TCIC_DATA              0x00
+#define TCIC_ADDR              0x02
+#define TCIC_SCTRL             0x06
+#define TCIC_SSTAT             0x07
+#define TCIC_MODE              0x08
+#define TCIC_PWR               0x09
+#define TCIC_EDC               0x0A
+#define TCIC_ICSR              0x0C
+#define TCIC_IENA              0x0D
+#define TCIC_AUX               0x0E
+
+#define TCIC_SS_SHFT           12
+#define TCIC_SS_MASK           0x7000
+
+/* Flags for TCIC_ADDR */
+#define TCIC_ADR2_REG          0x8000
+#define TCIC_ADR2_INDREG       0x0800
+
+#define TCIC_ADDR_REG          0x80000000
+#define TCIC_ADDR_SS_SHFT      (TCIC_SS_SHFT+16)
+#define TCIC_ADDR_SS_MASK      (TCIC_SS_MASK<<16)
+#define TCIC_ADDR_INDREG       0x08000000
+#define TCIC_ADDR_IO           0x04000000
+#define TCIC_ADDR_MASK         0x03ffffff
+
+/* Flags for TCIC_SCTRL */
+#define TCIC_SCTRL_ENA         0x01
+#define TCIC_SCTRL_INCMODE     0x18
+#define TCIC_SCTRL_INCMODE_HOLD        0x00
+#define TCIC_SCTRL_INCMODE_WORD        0x08
+#define TCIC_SCTRL_INCMODE_REG 0x10
+#define TCIC_SCTRL_INCMODE_AUTO        0x18
+#define TCIC_SCTRL_EDCSUM      0x20
+#define TCIC_SCTRL_RESET       0x80
+
+/* Flags for TCIC_SSTAT */
+#define TCIC_SSTAT_6US         0x01
+#define TCIC_SSTAT_10US                0x02
+#define TCIC_SSTAT_PROGTIME    0x04
+#define TCIC_SSTAT_LBAT1       0x08
+#define TCIC_SSTAT_LBAT2       0x10
+#define TCIC_SSTAT_RDY         0x20    /* Inverted */
+#define TCIC_SSTAT_WP          0x40
+#define TCIC_SSTAT_CD          0x80    /* Card detect */
+
+/* Flags for TCIC_MODE */
+#define TCIC_MODE_PGMMASK      0x1f
+#define TCIC_MODE_NORMAL       0x00
+#define TCIC_MODE_PGMWR                0x01
+#define TCIC_MODE_PGMRD                0x02
+#define TCIC_MODE_PGMCE                0x04
+#define TCIC_MODE_PGMDBW       0x08
+#define TCIC_MODE_PGMWORD      0x10
+#define TCIC_MODE_AUXSEL_MASK  0xe0
+
+/* Registers accessed through TCIC_AUX, by setting TCIC_MODE */
+#define TCIC_AUX_TCTL          (0<<5)
+#define TCIC_AUX_PCTL          (1<<5)
+#define TCIC_AUX_WCTL          (2<<5)
+#define TCIC_AUX_EXTERN                (3<<5)
+#define TCIC_AUX_PDATA         (4<<5)
+#define TCIC_AUX_SYSCFG                (5<<5)
+#define TCIC_AUX_ILOCK         (6<<5)
+#define TCIC_AUX_TEST          (7<<5)
+
+/* Flags for TCIC_PWR */
+#define TCIC_PWR_VCC(sock)     (0x01<<(sock))
+#define TCIC_PWR_VCC_MASK      0x03
+#define TCIC_PWR_VPP(sock)     (0x08<<(sock))
+#define TCIC_PWR_VPP_MASK      0x18
+#define TCIC_PWR_CLIMENA       0x40
+#define TCIC_PWR_CLIMSTAT      0x80
+
+/* Flags for TCIC_ICSR */
+#define TCIC_ICSR_CLEAR                0x01
+#define TCIC_ICSR_SET          0x02
+#define TCIC_ICSR_JAM          (TCIC_ICSR_CLEAR|TCIC_ICSR_SET)
+#define TCIC_ICSR_STOPCPU      0x04
+#define TCIC_ICSR_ILOCK                0x08
+#define TCIC_ICSR_PROGTIME     0x10
+#define TCIC_ICSR_ERR          0x20
+#define TCIC_ICSR_CDCHG                0x40
+#define TCIC_ICSR_IOCHK                0x80
+
+/* Flags for TCIC_IENA */
+#define TCIC_IENA_CFG_MASK     0x03
+#define TCIC_IENA_CFG_OFF      0x00    /* disabled */
+#define TCIC_IENA_CFG_OD       0x01    /* active low, open drain */
+#define TCIC_IENA_CFG_LOW      0x02    /* active low, totem pole */
+#define TCIC_IENA_CFG_HIGH     0x03    /* active high, totem pole */
+#define TCIC_IENA_ILOCK                0x08
+#define TCIC_IENA_PROGTIME     0x10
+#define TCIC_IENA_ERR          0x20    /* overcurrent or iochk */
+#define TCIC_IENA_CDCHG                0x40
+
+/* Flags for TCIC_AUX_WCTL */
+#define TCIC_WAIT_COUNT_MASK   0x001f
+#define TCIC_WAIT_ASYNC                0x0020
+#define TCIC_WAIT_SENSE                0x0040
+#define TCIC_WAIT_SRC          0x0080
+#define TCIC_WCTL_WR           0x0100
+#define TCIC_WCTL_RD           0x0200
+#define TCIC_WCTL_CE           0x0400
+#define TCIC_WCTL_LLBAT1       0x0800
+#define TCIC_WCTL_LLBAT2       0x1000
+#define TCIC_WCTL_LRDY         0x2000
+#define TCIC_WCTL_LWP          0x4000
+#define TCIC_WCTL_LCD          0x8000
+
+/* Flags for TCIC_AUX_SYSCFG */
+#define TCIC_SYSCFG_IRQ_MASK   0x000f
+#define TCIC_SYSCFG_MCSFULL    0x0010
+#define TCIC_SYSCFG_IO1723     0x0020
+#define TCIC_SYSCFG_MCSXB      0x0040
+#define TCIC_SYSCFG_ICSXB      0x0080
+#define TCIC_SYSCFG_NOPDN      0x0100
+#define TCIC_SYSCFG_MPSEL_SHFT 9
+#define TCIC_SYSCFG_MPSEL_MASK 0x0e00
+#define TCIC_SYSCFG_MPSENSE    0x2000
+#define TCIC_SYSCFG_AUTOBUSY   0x4000
+#define TCIC_SYSCFG_ACC                0x8000
+
+#define TCIC_ILOCK_OUT         0x01
+#define TCIC_ILOCK_SENSE       0x02
+#define TCIC_ILOCK_CRESET      0x04
+#define TCIC_ILOCK_CRESENA     0x08
+#define TCIC_ILOCK_CWAIT       0x10
+#define TCIC_ILOCK_CWAITSNS    0x20
+#define TCIC_ILOCK_HOLD_MASK   0xc0
+#define TCIC_ILOCK_HOLD_CCLK   0xc0
+
+#define TCIC_ILOCKTEST_ID_SH   8
+#define TCIC_ILOCKTEST_ID_MASK 0x7f00
+#define TCIC_ILOCKTEST_MCIC_1  0x8000
+
+#define TCIC_ID_DB86082                0x02
+#define TCIC_ID_DB86082A       0x03
+#define TCIC_ID_DB86084                0x04
+#define TCIC_ID_DB86084A       0x08
+#define TCIC_ID_DB86072                0x15
+#define TCIC_ID_DB86184                0x14
+#define TCIC_ID_DB86082B       0x17
+
+#define TCIC_TEST_DIAG         0x8000
+
+/*
+ * Indirectly addressed registers
+ */
+
+#define TCIC_SCF1(sock)        ((sock)<<3)
+#define TCIC_SCF2(sock) (((sock)<<3)+2)
+
+/* Flags for SCF1 */
+#define TCIC_SCF1_IRQ_MASK     0x000f
+#define TCIC_SCF1_IRQ_OFF      0x0000
+#define TCIC_SCF1_IRQOC                0x0010
+#define TCIC_SCF1_PCVT         0x0020
+#define TCIC_SCF1_IRDY         0x0040
+#define TCIC_SCF1_ATA          0x0080
+#define TCIC_SCF1_DMA_SHIFT    8
+#define TCIC_SCF1_DMA_MASK     0x0700
+#define TCIC_SCF1_DMA_OFF      0
+#define TCIC_SCF1_DREQ2                2
+#define TCIC_SCF1_IOSTS                0x0800
+#define TCIC_SCF1_SPKR         0x1000
+#define TCIC_SCF1_FINPACK      0x2000
+#define TCIC_SCF1_DELWR                0x4000
+#define TCIC_SCF1_HD7IDE       0x8000
+
+/* Flags for SCF2 */
+#define TCIC_SCF2_RI           0x0001
+#define TCIC_SCF2_IDBR         0x0002
+#define TCIC_SCF2_MDBR         0x0004
+#define TCIC_SCF2_MLBAT1       0x0008
+#define TCIC_SCF2_MLBAT2       0x0010
+#define TCIC_SCF2_MRDY         0x0020
+#define TCIC_SCF2_MWP          0x0040
+#define TCIC_SCF2_MCD          0x0080
+#define TCIC_SCF2_MALL         0x00f8
+
+/* Indirect addresses for memory window registers */
+#define TCIC_MWIN(sock,map)    (0x100+(((map)+((sock)<<2))<<3))
+#define TCIC_MBASE_X           2
+#define TCIC_MMAP_X            4
+#define TCIC_MCTL_X            6
+
+#define TCIC_MBASE_4K_BIT      0x4000
+#define TCIC_MBASE_HA_SHFT     12
+#define TCIC_MBASE_HA_MASK     0x0fff
+
+#define TCIC_MMAP_REG          0x8000
+#define TCIC_MMAP_CA_SHFT      12
+#define TCIC_MMAP_CA_MASK      0x3fff
+
+#define TCIC_MCTL_WSCNT_MASK   0x001f
+#define TCIC_MCTL_WCLK         0x0020
+#define TCIC_MCTL_WCLK_CCLK    0x0000
+#define TCIC_MCTL_WCLK_BCLK    0x0020
+#define TCIC_MCTL_QUIET                0x0040
+#define TCIC_MCTL_WP           0x0080
+#define TCIC_MCTL_ACC          0x0100
+#define TCIC_MCTL_KE           0x0200
+#define TCIC_MCTL_EDC          0x0400
+#define TCIC_MCTL_B8           0x0800
+#define TCIC_MCTL_SS_SHFT      TCIC_SS_SHFT
+#define TCIC_MCTL_SS_MASK      TCIC_SS_MASK
+#define TCIC_MCTL_ENA          0x8000
+
+/* Indirect addresses for I/O window registers */
+#define TCIC_IWIN(sock,map)    (0x200+(((map)+((sock)<<1))<<2))
+#define TCIC_IBASE_X           0
+#define TCIC_ICTL_X            2
+
+#define TCIC_ICTL_WSCNT_MASK   TCIC_MCTL_WSCNT_MASK
+#define TCIC_ICTL_QUIET                TCIC_MCTL_QUIET
+#define TCIC_ICTL_1K           0x0080
+#define TCIC_ICTL_PASS16       0x0100
+#define TCIC_ICTL_ACC          TCIC_MCTL_ACC
+#define TCIC_ICTL_TINY         0x0200
+#define TCIC_ICTL_B16          0x0400
+#define TCIC_ICTL_B8           TCIC_MCTL_B8
+#define TCIC_ICTL_BW_MASK      (TCIC_ICTL_B16|TCIC_ICTL_B8)
+#define TCIC_ICTL_BW_DYN       0
+#define TCIC_ICTL_BW_8         TCIC_ICTL_B8
+#define TCIC_ICTL_BW_16                TCIC_ICTL_B16
+#define TCIC_ICTL_BW_ATA       (TCIC_ICTL_B16|TCIC_ICTL_B8)
+#define TCIC_ICTL_SS_SHFT      TCIC_SS_SHFT
+#define TCIC_ICTL_SS_MASK      TCIC_SS_MASK
+#define TCIC_ICTL_ENA          TCIC_MCTL_ENA
+
+#endif /* _LINUX_TCIC_H */
diff --git a/drivers/pcmcia/ti113x.h b/drivers/pcmcia/ti113x.h
new file mode 100644 (file)
index 0000000..467750f
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * ti113x.h 1.14 1999/08/28 04:01:47
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_TI113X_H
+#define _LINUX_TI113X_H
+
+#ifndef PCI_VENDOR_ID_TI
+#define PCI_VENDOR_ID_TI               0x104c
+#endif
+
+#ifndef PCI_DEVICE_ID_TI_1130
+#define PCI_DEVICE_ID_TI_1130          0xac12
+#endif
+#ifndef PCI_DEVICE_ID_TI_1131
+#define PCI_DEVICE_ID_TI_1131          0xac15
+#endif
+#ifndef PCI_DEVICE_ID_TI_1031
+#define PCI_DEVICE_ID_TI_1031          0xac13
+#endif
+#ifndef PCI_DEVICE_ID_TI_1250A
+#define PCI_DEVICE_ID_TI_1250A         0xac16
+#endif
+#ifndef PCI_DEVICE_ID_TI_1220
+#define PCI_DEVICE_ID_TI_1220          0xac17
+#endif
+#ifndef PCI_DEVICE_ID_TI_1221
+#define PCI_DEVICE_ID_TI_1221          0xac19
+#endif
+#ifndef PCI_DEVICE_ID_TI_1210
+#define PCI_DEVICE_ID_TI_1210          0xac1a
+#endif
+#ifndef PCI_DEVICE_ID_TI_1251A
+#define PCI_DEVICE_ID_TI_1251A         0xac1d
+#endif
+#ifndef PCI_DEVICE_ID_TI_1251B
+#define PCI_DEVICE_ID_TI_1251B         0xac1f
+#endif
+#ifndef PCI_DEVICE_ID_TI_1450
+#define PCI_DEVICE_ID_TI_1450          0xac1b
+#endif
+#ifndef PCI_DEVICE_ID_TI_1225
+#define PCI_DEVICE_ID_TI_1225          0xac1c
+#endif
+
+/* Register definitions for TI 113X PCI-to-CardBus bridges */
+
+/* System Control Register */
+#define TI113X_SYSTEM_CONTROL          0x0080  /* 32 bit */
+#define  TI113X_SCR_SMIROUTE           0x04000000
+#define  TI113X_SCR_SMISTATUS          0x02000000
+#define  TI113X_SCR_SMIENB             0x01000000
+#define  TI113X_SCR_VCCPROT            0x00200000
+#define  TI113X_SCR_REDUCEZV           0x00100000
+#define  TI113X_SCR_CDREQEN            0x00080000
+#define  TI113X_SCR_CDMACHAN           0x00070000
+#define  TI113X_SCR_SOCACTIVE          0x00002000
+#define  TI113X_SCR_PWRSTREAM          0x00000800
+#define  TI113X_SCR_DELAYUP            0x00000400
+#define  TI113X_SCR_DELAYDOWN          0x00000200
+#define  TI113X_SCR_INTERROGATE                0x00000100
+#define  TI113X_SCR_CLKRUN_SEL         0x00000080
+#define  TI113X_SCR_PWRSAVINGS         0x00000040
+#define  TI113X_SCR_SUBSYSRW           0x00000020
+#define  TI113X_SCR_CB_DPAR            0x00000010
+#define  TI113X_SCR_CDMA_EN            0x00000008
+#define  TI113X_SCR_ASYNC_IRQ          0x00000004
+#define  TI113X_SCR_KEEPCLK            0x00000002
+#define  TI113X_SCR_CLKRUN_ENA         0x00000001  
+
+#define  TI122X_SCR_SER_STEP           0xc0000000
+#define  TI122X_SCR_INTRTIE            0x20000000
+#define  TI122X_SCR_CBRSVD             0x00400000
+#define  TI122X_SCR_MRBURSTDN          0x00008000
+#define  TI122X_SCR_MRBURSTUP          0x00004000
+#define  TI122X_SCR_RIMUX              0x00000001
+
+/* Multimedia Control Register */
+#define TI1250_MULTIMEDIA_CTL          0x0084  /* 8 bit */
+#define  TI1250_MMC_ZVOUTEN            0x80
+#define  TI1250_MMC_PORTSEL            0x40
+#define  TI1250_MMC_ZVEN1              0x02
+#define  TI1250_MMC_ZVEN0              0x01
+
+#define TI1250_GENERAL_STATUS          0x0085  /* 8 bit */
+#define TI1250_GPIO0_CONTROL           0x0088  /* 8 bit */
+#define TI1250_GPIO1_CONTROL           0x0089  /* 8 bit */
+#define TI1250_GPIO2_CONTROL           0x008a  /* 8 bit */
+#define TI1250_GPIO3_CONTROL           0x008b  /* 8 bit */
+#define TI122X_IRQMUX                  0x008c  /* 32 bit */
+
+/* Retry Status Register */
+#define TI113X_RETRY_STATUS            0x0090  /* 8 bit */
+#define  TI113X_RSR_PCIRETRY           0x80
+#define  TI113X_RSR_CBRETRY            0x40
+#define  TI113X_RSR_TEXP_CBB           0x20
+#define  TI113X_RSR_MEXP_CBB           0x10
+#define  TI113X_RSR_TEXP_CBA           0x08
+#define  TI113X_RSR_MEXP_CBA           0x04
+#define  TI113X_RSR_TEXP_PCI           0x02
+#define  TI113X_RSR_MEXP_PCI           0x01
+
+/* Card Control Register */
+#define TI113X_CARD_CONTROL            0x0091  /* 8 bit */
+#define  TI113X_CCR_RIENB              0x80
+#define  TI113X_CCR_ZVENABLE           0x40
+#define  TI113X_CCR_PCI_IRQ_ENA                0x20
+#define  TI113X_CCR_PCI_IREQ           0x10
+#define  TI113X_CCR_PCI_CSC            0x08
+#define  TI113X_CCR_SPKROUTEN          0x02
+#define  TI113X_CCR_IFG                        0x01
+
+#define  TI1220_CCR_PORT_SEL           0x20
+#define  TI122X_CCR_AUD2MUX            0x04
+
+/* Device Control Register */
+#define TI113X_DEVICE_CONTROL          0x0092  /* 8 bit */
+#define  TI113X_DCR_5V_FORCE           0x40
+#define  TI113X_DCR_3V_FORCE           0x20
+#define  TI113X_DCR_IMODE_MASK         0x06
+#define  TI113X_DCR_IMODE_ISA          0x02
+#define  TI113X_DCR_IMODE_SERIAL       0x04
+
+#define  TI12XX_DCR_IMODE_PCI_ONLY     0x00
+#define  TI12XX_DCR_IMODE_ALL_SERIAL   0x06
+
+/* Buffer Control Register */
+#define TI113X_BUFFER_CONTROL          0x0093  /* 8 bit */
+#define  TI113X_BCR_CB_READ_DEPTH      0x08
+#define  TI113X_BCR_CB_WRITE_DEPTH     0x04
+#define  TI113X_BCR_PCI_READ_DEPTH     0x02
+#define  TI113X_BCR_PCI_WRITE_DEPTH    0x01
+
+/* Diagnostic Register */
+#define TI1250_DIAGNOSTIC              0x0093  /* 8 bit */
+#define  TI1250_DIAG_TRUE_VALUE                0x80
+#define  TI1250_DIAG_PCI_IREQ          0x40
+#define  TI1250_DIAG_PCI_CSC           0x20
+#define  TI1250_DIAG_ASYNC_CSC         0x01
+
+/* DMA Registers */
+#define TI113X_DMA_0                   0x0094  /* 32 bit */
+#define TI113X_DMA_1                   0x0098  /* 32 bit */
+
+/* ExCA IO offset registers */
+#define TI113X_IO_OFFSET(map)          (0x36+((map)<<1))
+
+#endif /* _LINUX_TI113X_H */
+
diff --git a/drivers/pcmcia/topic.h b/drivers/pcmcia/topic.h
new file mode 100644 (file)
index 0000000..57860a0
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * topic.h 1.8 1999/08/28 04:01:47
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ * topic.h $Release$ 1999/08/28 04:01:47
+ */
+
+#ifndef _LINUX_TOPIC_H
+#define _LINUX_TOPIC_H
+
+#ifndef PCI_VENDOR_ID_TOSHIBA
+#define PCI_VENDOR_ID_TOSHIBA          0x1179
+#endif
+#ifndef PCI_DEVICE_ID_TOSHIBA_TOPIC95_A
+#define PCI_DEVICE_ID_TOSHIBA_TOPIC95_A        0x0603
+#endif
+#ifndef PCI_DEVICE_ID_TOSHIBA_TOPIC95_B
+#define PCI_DEVICE_ID_TOSHIBA_TOPIC95_B        0x060a
+#endif
+#ifndef PCI_DEVICE_ID_TOSHIBA_TOPIC97
+#define PCI_DEVICE_ID_TOSHIBA_TOPIC97  0x060f
+#endif
+
+/* Register definitions for Toshiba ToPIC95 controllers */
+
+#define TOPIC_SOCKET_CONTROL           0x0090  /* 32 bit */
+#define  TOPIC_SCR_IRQSEL              0x00000001
+
+#define TOPIC_SLOT_CONTROL             0x00a0  /* 8 bit */
+#define  TOPIC_SLOT_SLOTON             0x80
+#define  TOPIC_SLOT_SLOTEN             0x40
+#define  TOPIC_SLOT_ID_LOCK            0x20
+#define  TOPIC_SLOT_ID_WP              0x10
+#define  TOPIC_SLOT_PORT_MASK          0x0c
+#define  TOPIC_SLOT_PORT_SHIFT         2
+#define  TOPIC_SLOT_OFS_MASK           0x03
+
+#define TOPIC_CARD_CONTROL             0x00a1  /* 8 bit */
+#define  TOPIC_CCR_INTB                        0x20
+#define  TOPIC_CCR_INTA                        0x10
+#define  TOPIC_CCR_CLOCK               0x0c
+#define  TOPIC_CCR_PCICLK              0x0c
+#define  TOPIC_CCR_PCICLK_2            0x08
+#define  TOPIC_CCR_CCLK                        0x04
+
+#define TOPIC97_INT_CONTROL            0x00a1  /* 8 bit */
+#define  TOPIC97_ICR_INTB              0x20
+#define  TOPIC97_ICR_INTA              0x10
+#define  TOPIC97_ICR_STSIRQNP          0x04
+#define  TOPIC97_ICR_IRQNP             0x02
+#define  TOPIC97_ICR_IRQSEL            0x01
+
+#define TOPIC_CARD_DETECT              0x00a3  /* 8 bit */
+#define  TOPIC_CDR_MODE_PC32           0x80
+#define  TOPIC_CDR_VS1                 0x04
+#define  TOPIC_CDR_VS2                 0x02
+#define  TOPIC_CDR_SW_DETECT           0x01
+
+#define TOPIC_REGISTER_CONTROL         0x00a4  /* 32 bit */
+#define  TOPIC_RCR_RESUME_RESET                0x80000000
+#define  TOPIC_RCR_REMOVE_RESET                0x40000000
+#define  TOPIC97_RCR_CLKRUN_ENA                0x20000000
+#define  TOPIC97_RCR_TESTMODE          0x10000000
+#define  TOPIC97_RCR_IOPLUP            0x08000000
+#define  TOPIC_RCR_BUFOFF_PWROFF       0x02000000
+#define  TOPIC_RCR_BUFOFF_SIGOFF       0x01000000
+#define  TOPIC97_RCR_CB_DEV_MASK       0x0000f800
+#define  TOPIC97_RCR_CB_DEV_SHIFT      11
+#define  TOPIC97_RCR_RI_DISABLE                0x00000004
+#define  TOPIC97_RCR_CAUDIO_OFF                0x00000002
+#define  TOPIC_RCR_CAUDIO_INVERT       0x00000001
+
+#endif /* _LINUX_TOPIC_H */
diff --git a/drivers/pcmcia/vg468.h b/drivers/pcmcia/vg468.h
new file mode 100644 (file)
index 0000000..c19d53d
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * vg468.h 1.10 1999/08/28 04:01:47
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_VG468_H
+#define _LINUX_VG468_H
+
+/* Special bit in I365_IDENT used for Vadem chip detection */
+#define I365_IDENT_VADEM       0x08
+
+/* Special definitions in I365_POWER */
+#define VG468_VPP2_MASK                0x0c
+#define VG468_VPP2_5V          0x04
+#define VG468_VPP2_12V         0x08
+
+/* Unique Vadem registers */
+#define VG469_VSENSE           0x1f    /* Card voltage sense */
+#define VG469_VSELECT          0x2f    /* Card voltage select */
+#define VG468_CTL              0x38    /* Control register */
+#define VG468_TIMER            0x39    /* Timer control */
+#define VG468_MISC             0x3a    /* Miscellaneous */
+#define VG468_GPIO_CFG         0x3b    /* GPIO configuration */
+#define VG469_EXT_MODE         0x3c    /* Extended mode register */
+#define VG468_SELECT           0x3d    /* Programmable chip select */
+#define VG468_SELECT_CFG       0x3e    /* Chip select configuration */
+#define VG468_ATA              0x3f    /* ATA control */
+
+/* Flags for VG469_VSENSE */
+#define VG469_VSENSE_A_VS1     0x01
+#define VG469_VSENSE_A_VS2     0x02
+#define VG469_VSENSE_B_VS1     0x04
+#define VG469_VSENSE_B_VS2     0x08
+
+/* Flags for VG469_VSELECT */
+#define VG469_VSEL_VCC         0x03
+#define VG469_VSEL_5V          0x00
+#define VG469_VSEL_3V          0x03
+#define VG469_VSEL_MAX         0x0c
+#define VG469_VSEL_EXT_STAT    0x10
+#define VG469_VSEL_EXT_BUS     0x20
+#define VG469_VSEL_MIXED       0x40
+#define VG469_VSEL_ISA         0x80
+
+/* Flags for VG468_CTL */
+#define VG468_CTL_SLOW         0x01    /* 600ns memory timing */
+#define VG468_CTL_ASYNC                0x02    /* Asynchronous bus clocking */
+#define VG468_CTL_TSSI         0x08    /* Tri-state some outputs */
+#define VG468_CTL_DELAY                0x10    /* Card detect debounce */
+#define VG468_CTL_INPACK       0x20    /* Obey INPACK signal? */
+#define VG468_CTL_POLARITY     0x40    /* VCCEN polarity */
+#define VG468_CTL_COMPAT       0x80    /* Compatibility stuff */
+
+#define VG469_CTL_WS_COMPAT    0x04    /* Wait state compatibility */
+#define VG469_CTL_STRETCH      0x10    /* LED stretch */
+
+/* Flags for VG468_TIMER */
+#define VG468_TIMER_ZEROPWR    0x10    /* Zero power control */
+#define VG468_TIMER_SIGEN      0x20    /* Power up */
+#define VG468_TIMER_STATUS     0x40    /* Activity timer status */
+#define VG468_TIMER_RES                0x80    /* Timer resolution */
+#define VG468_TIMER_MASK       0x0f    /* Activity timer timeout */
+
+/* Flags for VG468_MISC */
+#define VG468_MISC_GPIO                0x04    /* General-purpose IO */
+#define VG468_MISC_DMAWSB      0x08    /* DMA wait state control */
+#define VG469_MISC_LEDENA      0x10    /* LED enable */
+#define VG468_MISC_VADEMREV    0x40    /* Vadem revision control */
+#define VG468_MISC_UNLOCK      0x80    /* Unique register lock */
+
+/* Flags for VG469_EXT_MODE_A */
+#define VG469_MODE_VPPST       0x03    /* Vpp steering control */
+#define VG469_MODE_INT_SENSE   0x04    /* Internal voltage sense */
+#define VG469_MODE_CABLE       0x08
+#define VG469_MODE_COMPAT      0x10    /* i82365sl B or DF step */
+#define VG469_MODE_TEST                0x20
+#define VG469_MODE_RIO         0x40    /* Steer RIO to INTR? */
+
+/* Flags for VG469_EXT_MODE_B */
+#define VG469_MODE_B_3V                0x01    /* 3.3v for socket B */
+
+#endif /* _LINUX_VG468_H */
diff --git a/drivers/pcmcia/yenta.h b/drivers/pcmcia/yenta.h
new file mode 100644 (file)
index 0000000..5c09f29
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * yenta.h 1.15 1999/08/28 04:01:47
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_YENTA_H
+#define _LINUX_YENTA_H
+
+/* PCI Configuration Registers */
+
+#define PCI_STATUS_CAPLIST             0x10
+#define PCI_CB_CAPABILITY_POINTER      0x14    /* 8 bit */
+#define PCI_CAPABILITY_ID              0x00    /* 8 bit */
+#define  PCI_CAPABILITY_PM             0x01
+#define PCI_NEXT_CAPABILITY            0x01    /* 8 bit */
+#define PCI_PM_CAPABILITIES            0x02    /* 16 bit */
+#define  PCI_PMCAP_PME_D3COLD          0x8000
+#define  PCI_PMCAP_PME_D3HOT           0x4000
+#define  PCI_PMCAP_PME_D2              0x2000
+#define  PCI_PMCAP_PME_D1              0x1000
+#define  PCI_PMCAP_PME_D0              0x0800
+#define  PCI_PMCAP_D2_CAP              0x0400
+#define  PCI_PMCAP_D1_CAP              0x0200
+#define  PCI_PMCAP_DYN_DATA            0x0100
+#define  PCI_PMCAP_DSI                 0x0020
+#define  PCI_PMCAP_AUX_PWR             0x0010
+#define  PCI_PMCAP_PMECLK              0x0008
+#define  PCI_PMCAP_VERSION_MASK                0x0007
+#define PCI_PM_CONTROL_STATUS          0x04    /* 16 bit */
+#define  PCI_PMCS_PME_STATUS           0x8000
+#define  PCI_PMCS_DATASCALE_MASK       0x6000
+#define  PCI_PMCS_DATASCALE_SHIFT      13
+#define  PCI_PMCS_DATASEL_MASK         0x1e00
+#define  PCI_PMCS_DATASEL_SHIFT                9
+#define  PCI_PMCS_PME_ENABLE           0x0100
+#define  PCI_PMCS_PWR_STATE_MASK       0x0003
+#define  PCI_PMCS_PWR_STATE_D0         0x0000
+#define  PCI_PMCS_PWR_STATE_D1         0x0001
+#define  PCI_PMCS_PWR_STATE_D2         0x0002
+#define  PCI_PMCS_PWR_STATE_D3         0x0003
+#define PCI_PM_BRIDGE_EXT              0x06    /* 8 bit */
+#define PCI_PM_DATA                    0x07    /* 8 bit */
+
+#define CB_PRIMARY_BUS                 0x18    /* 8 bit */
+#define CB_CARDBUS_BUS                 0x19    /* 8 bit */
+#define CB_SUBORD_BUS                  0x1a    /* 8 bit */
+#define CB_LATENCY_TIMER               0x1b    /* 8 bit */
+
+#define CB_MEM_BASE(m)                 (0x1c + 8*(m))
+#define CB_MEM_LIMIT(m)                        (0x20 + 8*(m))
+#define CB_IO_BASE(m)                  (0x2c + 8*(m))
+#define CB_IO_LIMIT(m)                 (0x30 + 8*(m))
+
+#define CB_BRIDGE_CONTROL              0x3e    /* 16 bit */
+#define  CB_BCR_PARITY_ENA             0x0001
+#define  CB_BCR_SERR_ENA               0x0002
+#define  CB_BCR_ISA_ENA                        0x0004
+#define  CB_BCR_VGA_ENA                        0x0008
+#define  CB_BCR_MABORT                 0x0020
+#define  CB_BCR_CB_RESET               0x0040
+#define  CB_BCR_ISA_IRQ                        0x0080
+#define  CB_BCR_PREFETCH(m)            (0x0100 << (m))
+#define  CB_BCR_WRITE_POST             0x0400
+
+#define CB_LEGACY_MODE_BASE            0x44
+
+/* Memory mapped registers */
+
+#define CB_SOCKET_EVENT                        0x0000
+#define  CB_SE_CSTSCHG                 0x00000001
+#define  CB_SE_CCD1                    0x00000002
+#define  CB_SE_CCD2                    0x00000004
+#define  CB_SE_PWRCYCLE                        0x00000008
+
+#define CB_SOCKET_MASK                 0x0004
+#define  CB_SM_CSTSCHG                 0x00000001
+#define  CB_SM_CCD                     0x00000006
+#define  CB_SM_PWRCYCLE                        0x00000008
+
+#define CB_SOCKET_STATE                        0x0008
+#define  CB_SS_CSTSCHG                 0x00000001
+#define  CB_SS_CCD1                    0x00000002
+#define  CB_SS_CCD2                    0x00000004
+#define  CB_SS_PWRCYCLE                        0x00000008
+#define  CB_SS_16BIT                   0x00000010
+#define  CB_SS_32BIT                   0x00000020
+#define  CB_SS_CINT                    0x00000040
+#define  CB_SS_BADCARD                 0x00000080
+#define  CB_SS_DATALOST                        0x00000100
+#define  CB_SS_BADVCC                  0x00000200
+#define  CB_SS_5VCARD                  0x00000400
+#define  CB_SS_3VCARD                  0x00000800
+#define  CB_SS_XVCARD                  0x00001000
+#define  CB_SS_YVCARD                  0x00002000
+#define  CB_SS_5VSOCKET                        0x10000000
+#define  CB_SS_3VSOCKET                        0x20000000
+#define  CB_SS_XVSOCKET                        0x40000000
+#define  CB_SS_YVSOCKET                        0x80000000
+
+#define CB_SOCKET_FORCE                        0x000c
+#define  CB_SF_CVSTEST                 0x00004000
+
+#define CB_SOCKET_CONTROL              0x0010
+#define  CB_SC_VPP_MASK                        0x00000007
+#define   CB_SC_VPP_OFF                        0x00000000
+#define   CB_SC_VPP_12V                        0x00000001
+#define   CB_SC_VPP_5V                 0x00000002
+#define   CB_SC_VPP_3V                 0x00000003
+#define   CB_SC_VPP_XV                 0x00000004
+#define   CB_SC_VPP_YV                 0x00000005
+#define  CB_SC_VCC_MASK                        0x00000070
+#define   CB_SC_VCC_OFF                        0x00000000
+#define   CB_SC_VCC_5V                 0x00000020
+#define   CB_SC_VCC_3V                 0x00000030
+#define   CB_SC_VCC_XV                 0x00000040
+#define   CB_SC_VCC_YV                 0x00000050
+#define  CB_SC_CCLK_STOP               0x00000080
+
+#define CB_SOCKET_POWER                        0x0020
+#define  CB_SP_CLK_CTRL                        0x00000001
+#define  CB_SP_CLK_CTRL_ENA            0x00010000
+#define  CB_SP_CLK_MODE                        0x01000000
+#define  CB_SP_ACCESS                  0x02000000
+
+/* Address bits 31..24 for memory windows for 16-bit cards,
+   accessable only by memory mapping the 16-bit register set */
+#define CB_MEM_PAGE(map)               (0x40 + (map))
+
+#endif /* _LINUX_YENTA_H */
index f465283611071bcf5f936fbe89bfe2d8e0a7495b..a31526d2451a9a7a4cf28caa3871ee3c9fff4106 100644 (file)
@@ -1,10 +1,10 @@
-/* $Id: advansys.c,v 1.50 1998/05/08 23:39:15 bobf Exp bobf $ */
-#define ASC_VERSION "3.1E"    /* AdvanSys Driver Version */
+/* $Id: advansys.c,v 1.58 1999/09/03 23:02:16 bobf Exp bobf $ */
+#define ASC_VERSION "3.2F"    /* AdvanSys Driver Version */
 
 /*
  * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
  * 
- * Copyright (c) 1995-1998 Advanced System Products, Inc.
+ * Copyright (c) 1995-1999 Advanced System Products, Inc.
  * All Rights Reserved.
  *
  * Redistribution and use in source and binary forms, with or without
   G. Driver Compile Time Options and Debugging
   H. Driver LILO Option
   I. Release History
-  J. Known Problems or Issues
+  J. Known Problems/Fix List
   K. Credits
   L. AdvanSys Contact Information
 
   A. Linux Kernel Testing
 
      This driver has been tested in the following Linux kernels: v1.2.13,
-     v1.3.57, v2.0.33, v2.1.77. These kernel versions are major releases
-     of Linux or the latest Linux kernel versions available when this version
-     of the driver was released. The driver should also work in earlier
-     versions of the Linux kernel. Beginning with v1.3.58 the AdvanSys driver
-     is included with all Linux kernels. Please refer to sections C, D, and
-     E for instructions on adding or upgrading the AdvanSys driver.
+     v1.3.57, v2.0.38, v2.2.12, and v2.3.16. These kernel versions are major
+     releases of Linux or the latest Linux kernel versions available when
+     this version of the driver was released. The driver should also work
+     in earlier versions of the Linux kernel. Beginning with v1.3.58 the
+     AdvanSys driver is included with all Linux kernels. Please refer to
+     sections C, D, and E for instructions on adding or upgrading the
+     AdvanSys driver.
 
   B. Adapters Supported by this Driver
  
      lowered in the BIOS by changing the 'Host Queue Size' adapter setting.
 
      Connectivity Products:
-        ABP510/5150 - Bus-Master ISA (240 CDB) (Footnote 1)
-        ABP5140 - Bus-Master ISA PnP (16 CDB) (Footnote 1, 3)
-        ABP5142 - Bus-Master ISA PnP with floppy (16 CDB) (Footnote 4)
+        ABP510/5150 - Bus-Master ISA (240 CDB)
+        ABP5140 - Bus-Master ISA PnP (16 CDB)
+        ABP5142 - Bus-Master ISA PnP with floppy (16 CDB)
+        ABP902/3902 - Bus-Master PCI (16 CDB)
+        ABP3905 - Bus-Master PCI (16 CDB)
+        ABP915 - Bus-Master PCI (16 CDB)
         ABP920 - Bus-Master PCI (16 CDB)
-        ABP930 - Bus-Master PCI (16 CDB) (Footnote 5)
+        ABP3922 - Bus-Master PCI (16 CDB)
+        ABP3925 - Bus-Master PCI (16 CDB)
+        ABP930 - Bus-Master PCI (16 CDB)
         ABP930U - Bus-Master PCI Ultra (16 CDB)
         ABP930UA - Bus-Master PCI Ultra (16 CDB)
-        ABP960 - Bus-Master PCI MAC/PC (16 CDB) (Footnote 2)
-        ABP960U - Bus-Master PCI MAC/PC Ultra (16 CDB) (Footnote 2)
+        ABP960 - Bus-Master PCI MAC/PC (16 CDB)
+        ABP960U - Bus-Master PCI MAC/PC Ultra (16 CDB)
      
      Single Channel Products:
         ABP542 - Bus-Master ISA with floppy (240 CDB)
         ABP842 - Bus-Master VL (240 CDB)
         ABP940 - Bus-Master PCI (240 CDB)
         ABP940U - Bus-Master PCI Ultra (240 CDB)
+        ABP940UA/3940UA - Bus-Master PCI Ultra (240 CDB)
         ABP970 - Bus-Master PCI MAC/PC (240 CDB)
         ABP970U - Bus-Master PCI MAC/PC Ultra (240 CDB)
-        ABP940UW - Bus-Master PCI Ultra-Wide (240 CDB)
+        ABP3960UA - Bus-Master PCI MAC/PC Ultra (240 CDB)
+        ABP940UW/3940UW - Bus-Master PCI Ultra-Wide (253 CDB)
+        ABP970UW - Bus-Master PCI MAC/PC Ultra-Wide (253 CDB)
+        ABP3940U2W - Bus-Master PCI LVD/Ultra2-Wide (253 CDB)
      
-     Multi Channel Products:
+     Multi-Channel Products:
         ABP752 - Dual Channel Bus-Master EISA (240 CDB Per Channel)
         ABP852 - Dual Channel Bus-Master VL (240 CDB Per Channel)
         ABP950 - Dual Channel Bus-Master PCI (240 CDB Per Channel)
+        ABP950UW - Dual Channel Bus-Master PCI Ultra-Wide (253 CDB Per Channel)
         ABP980 - Four Channel Bus-Master PCI (240 CDB Per Channel)
         ABP980U - Four Channel Bus-Master PCI Ultra (240 CDB Per Channel)
+        ABP980UA/3980UA - Four Channel Bus-Master PCI Ultra (16 CDB Per Chan.)
      
-     Footnotes:
-       1. This board has been shipped by HP with the 4020i CD-R drive.
-          The board has no BIOS so it cannot control a boot device, but
-          it can control any secondary SCSI device.
-       2. This board has been sold by Iomega as a Jaz Jet PCI adapter.
-       3. This board has been sold by SIIG as the i540 SpeedMaster.
-       4. This board has been sold by SIIG as the i542 SpeedMaster.
-       5. This board has been sold by SIIG as the Fast SCSI Pro PCI.
-
   C. Linux v1.2.X - Directions for Adding the AdvanSys Driver
 
      These directions apply to v1.2.13. For versions that follow v1.2.13.
             flag set to allow IRQ sharing with drivers that do not set
             the SA_INTERRUPT flag. Also display a more descriptive error
             message if request_irq() fails.
-         5. Update to latest Asc and Adv Libraries.
-
-  J. Known Problems or Issues
-
-         1. Remove conditional constants (ASC_QUEUE_FLOW_CONTROL) around
-            the queue depth flow control code when mid-level SCSI changes
-            are included in Linux.
+         6. Update to latest Asc and Adv Libraries.
+
+     3.2A (7/22/99):
+         1. Update Adv Library to 4.16 which includes support for
+            the ASC38C0800 (Ultra2/LVD) IC.
+
+     3.2B (8/23/99):
+         1. Correct PCI compile time option for v2.1.93 and greater
+            kernels, advansys_info() string, and debug compile time
+            option.
+         2. Correct DvcSleepMilliSecond() for v2.1.0 and greater
+            kernels. This caused an LVD detection/BIST problem problem
+            among other things.
+         3. Sort PCI cards by PCI Bus, Slot, Function ascending order
+            to be consistent with the BIOS.
+         4. Update to Asc Library S121 and Adv Library 5.2.
+
+     3.2C (8/24/99):
+         1. Correct PCI card detection bug introduced in 3.2B that
+            prevented PCI cards from being detected in kernels older
+            than v2.1.93.
+
+     3.2D (8/26/99):
+         1. Correct /proc device synchronous speed information display.
+            Also when re-negotiation is pending for a target device
+            note this condition with an * and footnote.
+         2. Correct initialization problem with Ultra-Wide cards that
+            have a pre-3.2 BIOS. A microcode variable changed locations
+            in 3.2 and greater BIOSes which caused WDTR to be attempted
+            erroneously with drives that don't support WDTR.
+
+     3.2E (8/30/99):
+         1. Fix compile error caused by v2.3.13 PCI structure change.
+         2. Remove field from ASCEEP_CONFIG that resulted in an EEPROM
+            checksum error for ISA cards.
+         3. Remove ASC_QUEUE_FLOW_CONTROL conditional code. The mid-level
+            SCSI changes that it depended on were never included in Linux.
+
+     3.2F (9/3/99):
+         1. Handle new initial function code added in v2.3.16 for all
+            driver versions.
+            
+  J. Known Problems/Fix List (XXX)
+
+     1. Need to add memory mapping workaround. Test the memory mapping.
+        If it doesn't work revert to I/O port access. Can a test be done
+        safely?
+     2. Handle an interrupt not working. Keep an interrupt counter in
+        the interrupt handler. In the timeout function if the interrupt
+        has not occurred then print a message and run in polled mode.
+     3. Allow bus type scanning order to be changed.
+     4. Need to add support for target mode commands, cf. CAM XPT.
+     5  Need to add support for new Linux SCSI error handling method.
+     6. Need to fix sti/cli code in Asc Library.
+     7. Need to fix abort code in Adv Library.
+     8. Reduce io_request_lock hold time.
+     9. Add big-endian support for Alpha.
 
   K. Credits
 
      Mark Moran <mmoran@mmoran.com> has helped test Ultra-Wide
      support in the 3.1A driver.
 
+     Doug Gilbert <dgilbert@interlog.com> has made changes and
+     suggestions to improve the driver and done testing.
+
   L. AdvanSys Contact Information
  
      Mail:                   Advanced System Products, Inc.
                              1150 Ringwood Court
                              San Jose, CA 95131
-     Operator:               1-408-383-9400
+     Operator/Sales:         1-408-383-9400
      FAX:                    1-408-383-9612
-     Tech Support:           1-800-525-7440/1-408-467-2930
-     BBS:                    1-408-383-9540 (14400,N,8,1)
-     Interactive FAX:        1-408-383-9753
-     Customer Direct Sales:  1-800-525-7443/1-408-383-5777
+     Tech Support:           1-408-467-2930
      Tech Support E-Mail:    support@advansys.com
      FTP Site:               ftp.advansys.com (login: anonymous)
      Web Site:               http://www.advansys.com
 #include <linux/string.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0)
+#include <linux/head.h>
+#endif /* verions < v2.1.0 */
 #include <linux/types.h>
 #include <linux/ioport.h>
 #include <linux/delay.h>
  */
 
 #define ASC_LIB_VERSION_MAJOR  1
-#define ASC_LIB_VERSION_MINOR  22
-#define ASC_LIB_SERIAL_NUMBER  113
+#define ASC_LIB_VERSION_MINOR  24
+#define ASC_LIB_SERIAL_NUMBER  121
 
 typedef unsigned char uchar;
 
@@ -832,6 +888,15 @@ typedef unsigned char uchar;
 #define  ASC_DVCLIB_CALL_FAILED   (0)
 #define  ASC_DVCLIB_CALL_ERROR    (-1)
 
+/*
+ * Enable CC_VERY_LONG_SG_LIST to support up to 64K element SG lists.
+ * The SRB structure will have to be changed and the ASC_SRB2SCSIQ()
+ * macro re-defined to be able to obtain a ASC_SCSI_Q pointer from the
+ * SRB structure.
+ */
+#define CC_VERY_LONG_SG_LIST 0
+#define ASC_SRB2SCSIQ(srb_ptr)  (srb_ptr)
+
 #define PortAddr            unsigned short    /* port address size  */
 #define Ptr2Func            ulong
 #define inp(port)           inb(port)
@@ -976,6 +1041,9 @@ typedef unsigned char uchar;
 #define SCSI_TYPE_COMM     0x09
 #define SCSI_TYPE_UNKNOWN  0x1F
 #define SCSI_TYPE_NO_DVC   0xFF
+#define INQ_CLOCKING_ST_ONLY    0x0
+#define INQ_CLOCKING_DT_ONLY    0x1
+#define INQ_CLOCKING_ST_AND_DT  0x3
 #define ASC_SCSIDIR_NOCHK    0x00
 #define ASC_SCSIDIR_T2H      0x08
 #define ASC_SCSIDIR_H2T      0x10
@@ -1194,9 +1262,10 @@ typedef struct asc_req_sense {
 #define ASC_SCSIQ_CDB_BEG             36
 #define ASC_SCSIQ_DW_REMAIN_XFER_ADDR 56
 #define ASC_SCSIQ_DW_REMAIN_XFER_CNT  60
+#define ASC_SCSIQ_B_FIRST_SG_WK_QP    48
 #define ASC_SCSIQ_B_SG_WK_QP          49
 #define ASC_SCSIQ_B_SG_WK_IX          50
-#define ASC_SCSIQ_W_REQ_COUNT         52
+#define ASC_SCSIQ_W_ALT_DC1           52
 #define ASC_SCSIQ_B_LIST_CNT          6
 #define ASC_SCSIQ_B_CUR_LIST_CNT      7
 #define ASC_SGQ_B_SG_CNTL             4
@@ -1307,6 +1376,8 @@ typedef struct asc_scsi_q {
     ASC_SCSIQ_2         q2;
     uchar               *cdbptr;
     ASC_SG_HEAD         *sg_head;
+    ushort              remain_sg_entry_cnt;
+    ushort              next_sg_index;
 } ASC_SCSI_Q;
 
 typedef struct asc_scsi_req_q {
@@ -1781,6 +1852,7 @@ typedef struct asceep_config {
 #define ASC_HALT_DISABLE_ASYN_USE_SYN_FIX  (ushort)0x8300
 #define ASC_HALT_ENABLE_ASYN_USE_SYN_FIX   (ushort)0x8400
 #define ASC_HALT_SDTR_REJECTED (ushort)0x4000
+#define ASC_HALT_HOST_COPY_SG_LIST_TO_RISC ( ushort )0x2000
 #define ASC_MAX_QNO        0xF8
 #define ASC_DATA_SEC_BEG   (ushort)0x0080
 #define ASC_DATA_SEC_END   (ushort)0x0080
@@ -1876,10 +1948,10 @@ typedef struct asc_mc_saved {
 #define AscGetRiscVarDoneQTail(port)        AscReadLramByte((port), ASCV_DONENEXT_B)
 #define AscPutRiscVarFreeQHead(port, val)   AscWriteLramByte((port), ASCV_NEXTRDY_B, val)
 #define AscPutRiscVarDoneQTail(port, val)   AscWriteLramByte((port), ASCV_DONENEXT_B, val)
-#define AscPutMCodeSDTRDoneAtID(port, id, data)  AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id), (data)) ;
-#define AscGetMCodeSDTRDoneAtID(port, id)        AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id)) ;
-#define AscPutMCodeInitSDTRAtID(port, id, data)  AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id), data) ;
-#define AscGetMCodeInitSDTRAtID(port, id)        AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id)) ;
+#define AscPutMCodeSDTRDoneAtID(port, id, data)  AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id), (data));
+#define AscGetMCodeSDTRDoneAtID(port, id)        AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id));
+#define AscPutMCodeInitSDTRAtID(port, id, data)  AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id), data);
+#define AscGetMCodeInitSDTRAtID(port, id)        AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id));
 #define AscSynIndexToPeriod(index)        (uchar)(asc_dvc->sdtr_period_tbl[ (index) ])
 #define AscGetChipSignatureByte(port)     (uchar)inp((port)+IOP_SIG_BYTE)
 #define AscGetChipSignatureWord(port)     (ushort)inpw((port)+IOP_SIG_WORD)
@@ -2074,8 +2146,8 @@ STATIC ulong     AscGetMaxDmaCount(ushort);
  * --- Adv Library Constants and Macros
  */
 
-#define ADV_LIB_VERSION_MAJOR  3
-#define ADV_LIB_VERSION_MINOR  45
+#define ADV_LIB_VERSION_MAJOR  5
+#define ADV_LIB_VERSION_MINOR  2
 
 /* d_os_dep.h */
 #define ADV_OS_LINUX
@@ -2105,6 +2177,8 @@ STATIC ulong     AscGetMaxDmaCount(ushort);
 #define iounmap vfree
 #endif /* version < v2.1.0 */
 
+#define ADV_CARRIER_COUNT (ASC_DEF_MAX_HOST_QNG + 15)
+
 /*
  * Define total number of simultaneous maximum element scatter-gather
  * requests, i.e. ADV_TOT_SG_LIST * ADV_MAX_SG_LIST is the total number
@@ -2117,18 +2191,9 @@ STATIC ulong     AscGetMaxDmaCount(ushort);
  */
 #define ADV_MAX_SG_LIST         64
 
-/*
- * Scatter-Gather Definitions per request.
- *
- * Because SG block memory is allocated in virtual memory but is
- * referenced by the microcode as physical memory, we need to do
- * calculations to insure there will be enough physically contiguous
- * memory to support ADV_MAX_SG_LIST SG entries.
- */
-
 /* Number of SG blocks needed. */
 #define ADV_NUM_SG_BLOCK \
-     ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK)
+    ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK)
 
 /* Total contiguous memory needed for SG blocks. */
 #define ADV_SG_TOTAL_MEM_SIZE \
@@ -2136,26 +2201,16 @@ STATIC ulong     AscGetMaxDmaCount(ushort);
 
 #define ASC_PAGE_SIZE PAGE_SIZE
 
-/*
- * Number of page crossings possible for the total contiguous virtual memory
- * needed for SG blocks.
- *
- * We need to allocate this many additional SG blocks in virtual memory to
- * insure there will be space for ADV_NUM_SG_BLOCK physically contiguous
- * scatter-gather blocks.
- */
 #define ADV_NUM_PAGE_CROSSING \
     ((ADV_SG_TOTAL_MEM_SIZE + (ASC_PAGE_SIZE - 1))/ASC_PAGE_SIZE)
 
-/*
- * Define Adv Library Assertion Macro.
- */
-
 #define ADV_ASSERT(a) ASC_ASSERT(a)
 
 /* a_condor.h */
 #define ADV_PCI_VENDOR_ID               0x10CD
 #define ADV_PCI_DEVICE_ID_REV_A         0x2300
+#define ADV_PCI_DEVID_38C0800_REV1      0x2500
+#define ADV_PCI_DEVID_38C1600_REV1      0x2700
 
 #define ASC_EEP_DVC_CFG_BEGIN           (0x00)
 #define ASC_EEP_DVC_CFG_END             (0x15)
@@ -2164,31 +2219,13 @@ STATIC ulong     AscGetMaxDmaCount(ushort);
 
 #define ASC_EEP_DELAY_MS                100
 
-/*
- * EEPROM bits reference by the RISC after initialization.
- */
 #define ADV_EEPROM_BIG_ENDIAN          0x8000   /* EEPROM Bit 15 */
 #define ADV_EEPROM_BIOS_ENABLE         0x4000   /* EEPROM Bit 14 */
 #define ADV_EEPROM_TERM_POL            0x2000   /* EEPROM Bit 13 */
+#define ADV_EEPROM_CIS_LD              0x1000   /* EEPROM Bit 12 */
 
-/*
- * EEPROM configuration format
- *
- * Field naming convention: 
- *
- *  *_enable indicates the field enables or disables the feature. The
- *  value is never reset.
- *
- *  *_able indicates both whether a feature should be enabled or disabled
- *  and whether a device isi capable of the feature. At initialization
- *  this field may be set, but later if a device is found to be incapable
- *  of the feature, the field is cleared.
- *
- * Default values are maintained in a_init.c in the structure
- * Default_EEPROM_Config.
- */
-typedef struct adveep_config
-{                              
+typedef struct adveep_3550_config
+{
                                 /* Word Offset, Description */
 
   ushort cfg_lsw;               /* 00 power up initialization */
@@ -2255,7 +2292,109 @@ typedef struct adveep_config
   ushort  saved_adv_err_code;   /* 34 saved last uc and Adv Lib error code */
   ushort  saved_adv_err_addr;   /* 35 saved last uc error address         */  
   ushort  num_of_err;           /* 36 number of error */
-} ADVEEP_CONFIG; 
+} ADVEEP_3550_CONFIG; 
+
+typedef struct adveep_38C0800_config
+{
+                                /* Word Offset, Description */
+
+  ushort cfg_lsw;               /* 00 power up initialization */
+                                /*  bit 12 set - CIS Load */
+                                /*  bit 13 set - Term Polarity Control */
+                                /*  bit 14 set - BIOS Enable */
+                                /*  bit 15 set - Big Endian Mode */
+  ushort cfg_msw;               /* 01 unused      */
+  ushort disc_enable;           /* 02 disconnect enable */
+  ushort wdtr_able;             /* 03 Wide DTR able */
+  ushort sdtr_speed1;           /* 04 SDTR Speed TID 0-3 */
+  ushort start_motor;           /* 05 send start up motor */
+  ushort tagqng_able;           /* 06 tag queuing able */
+  ushort bios_scan;             /* 07 BIOS device control */
+  ushort scam_tolerant;         /* 08 no scam */
+
+  uchar  adapter_scsi_id;       /* 09 Host Adapter ID */
+  uchar  bios_boot_delay;       /*    power up wait */
+
+  uchar  scsi_reset_delay;      /* 10 reset delay */
+  uchar  bios_id_lun;           /*    first boot device scsi id & lun */
+                                /*    high nibble is lun */
+                                /*    low nibble is scsi id */
+
+  uchar  termination_se;        /* 11 0 - automatic */
+                                /*    1 - low off / high off */
+                                /*    2 - low off / high on */
+                                /*    3 - low on  / high on */
+                                /*    There is no low on  / high off */
+
+  uchar  termination_lvd;       /* 11 0 - automatic */
+                                /*    1 - low off / high off */
+                                /*    2 - low off / high on */
+                                /*    3 - low on  / high on */
+                                /*    There is no low on  / high off */
+
+  ushort bios_ctrl;             /* 12 BIOS control bits */
+                                /*  bit 0  set: BIOS don't act as initiator. */
+                                /*  bit 1  set: BIOS > 1 GB support */
+                                /*  bit 2  set: BIOS > 2 Disk Support */
+                                /*  bit 3  set: BIOS don't support removables */
+                                /*  bit 4  set: BIOS support bootable CD */
+                                /*  bit 5  set: BIOS scan enabled */
+                                /*  bit 6  set: BIOS support multiple LUNs */
+                                /*  bit 7  set: BIOS display of message */
+                                /*  bit 8  set: */
+                                /*  bit 9  set: Reset SCSI bus during init. */
+                                /*  bit 10 set: */
+                                /*  bit 11 set: No verbose initialization. */
+                                /*  bit 12 set: SCSI parity enabled */
+                                /*  bit 13 set: */
+                                /*  bit 14 set: */
+                                /*  bit 15 set: */
+  ushort  sdtr_speed2;          /* 13 SDTR speed TID 4-7 */
+  ushort  sdtr_speed3;          /* 14 SDTR speed TID 8-11 */
+  uchar   max_host_qng;         /* 15 maximum host queueing */
+  uchar   max_dvc_qng;          /*    maximum per device queuing */
+  ushort  dvc_cntl;             /* 16 control bit for driver */
+  ushort  sdtr_speed4;          /* 17 SDTR speed 4 TID 12-15 */
+  ushort  serial_number_word1;  /* 18 Board serial number word 1 */
+  ushort  serial_number_word2;  /* 19 Board serial number word 2 */
+  ushort  serial_number_word3;  /* 20 Board serial number word 3 */
+  ushort  check_sum;            /* 21 EEP check sum */
+  uchar   oem_name[16];         /* 22 OEM name */
+  ushort  dvc_err_code;         /* 30 last device driver error code */
+  ushort  adv_err_code;         /* 31 last uc and Adv Lib error code */
+  ushort  adv_err_addr;         /* 32 last uc error address */
+  ushort  saved_dvc_err_code;   /* 33 saved last dev. driver error code   */
+  ushort  saved_adv_err_code;   /* 34 saved last uc and Adv Lib error code */
+  ushort  saved_adv_err_addr;   /* 35 saved last uc error address         */
+  ushort  reserved36;           /* 36 reserved */
+  ushort  reserved37;           /* 37 reserved */
+  ushort  reserved38;           /* 38 reserved */
+  ushort  reserved39;           /* 39 reserved */
+  ushort  reserved40;           /* 40 reserved */
+  ushort  reserved41;           /* 41 reserved */
+  ushort  reserved42;           /* 42 reserved */
+  ushort  reserved43;           /* 43 reserved */
+  ushort  reserved44;           /* 44 reserved */
+  ushort  reserved45;           /* 45 reserved */
+  ushort  reserved46;           /* 46 reserved */
+  ushort  reserved47;           /* 47 reserved */
+  ushort  reserved48;           /* 48 reserved */
+  ushort  reserved49;           /* 49 reserved */
+  ushort  reserved50;           /* 50 reserved */
+  ushort  reserved51;           /* 51 reserved */
+  ushort  reserved52;           /* 52 reserved */
+  ushort  reserved53;           /* 53 reserved */
+  ushort  reserved54;           /* 54 reserved */
+  ushort  reserved55;           /* 55 reserved */
+  ushort  cisptr_lsw;           /* 56 CIS PTR LSW */
+  ushort  cisprt_msw;           /* 57 CIS PTR MSW */
+  ushort  subsysvid;            /* 58 SubSystem Vendor ID */
+  ushort  subsysid;             /* 59 SubSystem ID */
+  ushort  reserved60;           /* 60 reserved */
+  ushort  reserved61;           /* 61 reserved */
+  ushort  reserved62;           /* 62 reserved */
+  ushort  reserved63;           /* 63 reserved */
+} ADVEEP_38C0800_CONFIG;
 
 /*
  * EEPROM Commands
@@ -2279,15 +2418,15 @@ typedef struct adveep_config
 #define BIOS_CTRL_INIT_VERBOSE       0x0800
 #define BIOS_CTRL_SCSI_PARITY        0x1000
 
-/*
- * ASC 3550 Internal Memory Size - 8KB
- */
-#define ADV_CONDOR_MEMSIZE   0x2000     /* 8 KB Internal Memory */
+#define ADV_3550_MEMSIZE   0x2000       /* 8 KB Internal Memory */
+#define ADV_3550_IOLEN     0x40         /* I/O Port Range in bytes */
 
-/*
- * ASC 3550 I/O Length - 64 bytes
- */
-#define ADV_CONDOR_IOLEN     0x40       /* I/O Port Range in bytes */
+#define ADV_38C0800_MEMSIZE  0x4000     /* 16 KB Internal Memory */
+#define ADV_38C0800_IOLEN    0x100      /* I/O Port Range in bytes */
+
+#define ADV_38C1600_MEMSIZE  0x4000    /* 16 KB Internal Memory */
+#define ADV_38C1600_IOLEN    0x100     /* I/O Port Range 256 bytes */
+#define ADV_38C1600_MEMLEN   0x1000    /* Memory Range 4KB bytes */
 
 /*
  * Byte I/O register address from base of 'iop_base'.
@@ -2306,11 +2445,11 @@ typedef struct adveep_config
 #define IOPB_RES_ADDR_B         0x0B
 #define IOPB_RES_ADDR_C         0x0C
 #define IOPB_RES_ADDR_D         0x0D
-#define IOPB_RES_ADDR_E         0x0E
+#define IOPB_SOFT_OVER_WR       0x0E
 #define IOPB_RES_ADDR_F         0x0F
 #define IOPB_MEM_CFG            0x10
-#define IOPB_RES_ADDR_11        0x11
-#define IOPB_RES_ADDR_12        0x12
+#define IOPB_GPIO_CNTL          0x11
+#define IOPB_GPIO_DATA          0x12
 #define IOPB_RES_ADDR_13        0x13
 #define IOPB_FLASH_PAGE         0x14
 #define IOPB_RES_ADDR_15        0x15
@@ -2348,8 +2487,8 @@ typedef struct adveep_config
 #define IOPB_RES_ADDR_35        0x35
 #define IOPB_RES_ADDR_36        0x36
 #define IOPB_RES_ADDR_37        0x37
-#define IOPB_RES_ADDR_38        0x38
-#define IOPB_RES_ADDR_39        0x39
+#define IOPB_RAM_BIST           0x38
+#define IOPB_PLL_TEST           0x39
 #define IOPB_RES_ADDR_3A        0x3A
 #define IOPB_RES_ADDR_3B        0x3B
 #define IOPB_RFIFO_CNT          0x3C
@@ -2402,8 +2541,8 @@ typedef struct adveep_config
 #define IOPDW_RES_ADDR_8         0x08
 #define IOPDW_RES_ADDR_C         0x0C
 #define IOPDW_RES_ADDR_10        0x10
-#define IOPDW_RES_ADDR_14        0x14
-#define IOPDW_RES_ADDR_18        0x18
+#define IOPDW_COMMA              0x14
+#define IOPDW_COMMB              0x18
 #define IOPDW_RES_ADDR_1C        0x1C
 #define IOPDW_SDMA_ADDR0         0x20
 #define IOPDW_SDMA_ADDR1         0x24
@@ -2453,9 +2592,14 @@ typedef struct adveep_config
 #define ADV_CTRL_REG_CMD_WR_PCI_CFG_SPACE  0x00C3
 #define ADV_CTRL_REG_CMD_RD_PCI_CFG_SPACE  0x00C2
 
+#define ADV_TICKLE_NOP                      0x00
+#define ADV_TICKLE_A                        0x01
+#define ADV_TICKLE_B                        0x02
+#define ADV_TICKLE_C                        0x03
+
 #define ADV_SCSI_CTRL_RSTOUT        0x2000
 
-#define AdvIsIntPending(port)  \
+#define AdvIsIntPending(port) \
     (AdvReadWordRegister(port, IOPW_CTRL_REG) & ADV_CTRL_REG_HOST_INTR)
 
 /*
@@ -2492,41 +2636,34 @@ typedef struct adveep_config
 #define  TERM_CTL_L      0x0010  /* Enable External SCSI Lower Termination */
 #define CABLE_DETECT    0x000F  /* External SCSI Cable Connection Status */
 
+/*
+ * Addendum for ASC-38C0800 Chip
+ */
+#define DIS_TERM_DRV    0x4000  /* 1: Read c_det[3:0], 0: cannot read */
+#define HVD_LVD_SE      0x1C00  /* Device Detect Bits */
+#define  HVD             0x1000  /* HVD Device Detect */
+#define  LVD             0x0800  /* LVD Device Detect */
+#define  SE              0x0400  /* SE Device Detect */
+#define TERM_LVD        0x00C0  /* LVD Termination Bits */
+#define  TERM_LVD_HI     0x0080  /* Enable LVD Upper Termination */
+#define  TERM_LVD_LO     0x0040  /* Enable LVD Lower Termination */
+#define TERM_SE         0x0030  /* SE Termination Bits */
+#define  TERM_SE_HI      0x0020  /* Enable SE Upper Termination */
+#define  TERM_SE_LO      0x0010  /* Enable SE Lower Termination */
+#define C_DET_LVD       0x000C  /* LVD Cable Detect Bits */
+#define  C_DET3          0x0008  /* Cable Detect for LVD External Wide */
+#define  C_DET2          0x0004  /* Cable Detect for LVD Internal Wide */
+#define C_DET_SE        0x0003  /* SE Cable Detect Bits */
+#define  C_DET1          0x0002  /* Cable Detect for SE Internal Wide */
+#define  C_DET0          0x0001  /* Cable Detect for SE Internal Narrow */
+
+
 #define CABLE_ILLEGAL_A 0x7
     /* x 0 0 0  | on  on | Illegal (all 3 connectors are used) */
 
 #define CABLE_ILLEGAL_B 0xB
     /* 0 x 0 0  | on  on | Illegal (all 3 connectors are used) */
 
-/*
-   The following table details the SCSI_CFG1 Termination Polarity,
-   Termination Control and Cable Detect bits.
-
-   Cable Detect | Termination
-   Bit 3 2 1 0  | 5   4  | Notes
-   _____________|________|____________________
-       1 1 1 0  | on  on | Internal wide only
-       1 1 0 1  | on  on | Internal narrow only
-       1 0 1 1  | on  on | External narrow only
-       0 x 1 1  | on  on | External wide only
-       1 1 0 0  | on  off| Internal wide and internal narrow
-       1 0 1 0  | on  off| Internal wide and external narrow
-       0 x 1 0  | off off| Internal wide and external wide
-       1 0 0 1  | on  off| Internal narrow and external narrow
-       0 x 0 1  | on  off| Internal narrow and external wide
-       1 1 1 1  | on  on | No devices are attached
-       x 0 0 0  | on  on | Illegal (all 3 connectors are used)
-       0 x 0 0  | on  on | Illegal (all 3 connectors are used)
-  
-       x means don't-care (either '0' or '1')
-  
-       If term_pol (bit 13) is '0' (active-low terminator enable), then:
-           'on' is '0' and 'off' is '1'.
-  
-       If term_pol bit is '1' (meaning active-hi terminator enable), then:
-           'on' is '1' and 'off' is '0'.
- */
-
 /*
  * MEM_CFG Register bit definitions
  */
@@ -2564,6 +2701,22 @@ typedef struct adveep_config
 #define  READ_CMD_MRL    0x02    /* Memory Read Long */
 #define  READ_CMD_MRM    0x03    /* Memory Read Multiple (default) */
 
+/*
+ * ASC-38C0800 RAM BIST Register bit definitions
+ */
+#define RAM_TEST_MODE         0x80
+#define PRE_TEST_MODE         0x40
+#define NORMAL_MODE           0x00
+#define RAM_TEST_DONE         0x10
+#define RAM_TEST_STATUS       0x0F
+#define  RAM_TEST_HOST_ERROR   0x08
+#define  RAM_TEST_INTRAM_ERROR 0x04
+#define  RAM_TEST_RISC_ERROR   0x02
+#define  RAM_TEST_SCSI_ERROR   0x01
+#define  RAM_TEST_SUCCESS      0x00
+#define PRE_TEST_VALUE        0x05
+#define NORMAL_VALUE          0x00
+
 /* a_advlib.h */
 
 /*
@@ -2580,6 +2733,7 @@ typedef struct adveep_config
 /*
  * ASC_DVC_VAR 'warn_code' values
  */
+#define ASC_WARN_BUSRESET_ERROR         0x0001 /* SCSI Bus Reset error */
 #define ASC_WARN_EEPROM_CHKSUM          0x0002 /* EEP check sum error */
 #define ASC_WARN_EEPROM_TERMINATION     0x0004 /* EEP termination bad field */
 #define ASC_WARN_SET_PCI_CONFIG_SPACE   0x0080 /* PCI config space set error */
@@ -2596,14 +2750,18 @@ typedef struct adveep_config
  */
 #define ASC_IERR_WRITE_EEPROM       0x0001 /* write EEPROM error */
 #define ASC_IERR_MCODE_CHKSUM       0x0002 /* micro code check sum error */
+#define ASC_IERR_NO_CARRIER         0x0004 /* No more carrier memory. */
 #define ASC_IERR_START_STOP_CHIP    0x0008 /* start/stop chip failed */
 #define ASC_IERR_CHIP_VERSION       0x0040 /* wrong chip version */
 #define ASC_IERR_SET_SCSI_ID        0x0080 /* set SCSI ID failed */
+#define ASC_IERR_HVD_DEVICE         0x0100 /* HVD attached to LVD connector. */
 #define ASC_IERR_BAD_SIGNATURE      0x0200 /* signature not found */
 #define ASC_IERR_ILLEGAL_CONNECTION 0x0400 /* Illegal cable connection */
 #define ASC_IERR_SINGLE_END_DEVICE  0x0800 /* Single-end used w/differential */
 #define ASC_IERR_REVERSED_CABLE     0x1000 /* Narrow flat cable reversed */
-#define ASC_IERR_RW_LRAM            0x8000 /* read/write local RAM error */
+#define ASC_IERR_BIST_PRE_TEST      0x2000 /* BIST pre-test error */
+#define ASC_IERR_BIST_RAM_TEST      0x4000 /* BIST RAM test error */
+#define ASC_IERR_BAD_CHIPTYPE       0x8000 /* Invalid 'chip_type' setting. */
 
 /*
  * Fixed locations of microcode operating variables.
@@ -2611,37 +2769,38 @@ typedef struct adveep_config
 #define ASC_MC_CODE_BEGIN_ADDR          0x0028 /* microcode start address */
 #define ASC_MC_CODE_END_ADDR            0x002A /* microcode end address */
 #define ASC_MC_CODE_CHK_SUM             0x002C /* microcode code checksum */
-#define ASC_MC_STACK_BEGIN              0x002E /* microcode stack begin */
-#define ASC_MC_STACK_END                0x0030 /* microcode stack end */
 #define ASC_MC_VERSION_DATE             0x0038 /* microcode version */
 #define ASC_MC_VERSION_NUM              0x003A /* microcode number */
-#define ASCV_VER_SERIAL_W               0x003C /* used in dos_init */
 #define ASC_MC_BIOSMEM                  0x0040 /* BIOS RISC Memory Start */
 #define ASC_MC_BIOSLEN                  0x0050 /* BIOS RISC Memory Length */
-#define ASC_MC_HALTCODE                 0x0094 /* microcode halt code */
-#define ASC_MC_CALLERPC                 0x0096 /* microcode halt caller PC */
-#define ASC_MC_ADAPTER_SCSI_ID          0x0098 /* one ID byte + reserved */
-#define ASC_MC_ULTRA_ABLE               0x009C
+#define ASC_MC_BIOS_SIGNATURE           0x0058 /* BIOS Signature 0x55AA */
+#define ASC_MC_BIOS_VERSION             0x005A /* BIOS Version (2 bytes) */
+#define ASC_MC_SDTR_SPEED1              0x0090 /* SDTR Speed for TID 0-3 */
+#define ASC_MC_SDTR_SPEED2              0x0092 /* SDTR Speed for TID 4-7 */
+#define ASC_MC_SDTR_SPEED3              0x0094 /* SDTR Speed for TID 8-11 */
+#define ASC_MC_SDTR_SPEED4              0x0096 /* SDTR Speed for TID 12-15 */
+#define ASC_MC_CHIP_TYPE                0x009A
+#define ASC_MC_INTRB_CODE               0x009B
+#define ASC_MC_WDTR_ABLE                0x009C
 #define ASC_MC_SDTR_ABLE                0x009E
 #define ASC_MC_TAGQNG_ABLE              0x00A0
 #define ASC_MC_DISC_ENABLE              0x00A2
+#define ASC_MC_IDLE_CMD_STATUS          0x00A4
 #define ASC_MC_IDLE_CMD                 0x00A6
-#define ASC_MC_IDLE_PARA_STAT           0x00A8
+#define ASC_MC_IDLE_CMD_PARAMETER       0x00A8
 #define ASC_MC_DEFAULT_SCSI_CFG0        0x00AC
 #define ASC_MC_DEFAULT_SCSI_CFG1        0x00AE
 #define ASC_MC_DEFAULT_MEM_CFG          0x00B0
 #define ASC_MC_DEFAULT_SEL_MASK         0x00B2
-#define ASC_MC_RISC_NEXT_READY          0x00B4
-#define ASC_MC_RISC_NEXT_DONE           0x00B5
 #define ASC_MC_SDTR_DONE                0x00B6
 #define ASC_MC_NUMBER_OF_QUEUED_CMD     0x00C0
 #define ASC_MC_NUMBER_OF_MAX_CMD        0x00D0
 #define ASC_MC_DEVICE_HSHK_CFG_TABLE    0x0100
-#define ASC_MC_WDTR_ABLE                0x0120 /* Wide Transfer TID bitmask. */
 #define ASC_MC_CONTROL_FLAG             0x0122 /* Microcode control flag. */
 #define ASC_MC_WDTR_DONE                0x0124
-#define ASC_MC_HOST_NEXT_READY          0x0128 /* Host Next Ready RQL Entry. */
-#define ASC_MC_HOST_NEXT_DONE           0x0129 /* Host Next Done RQL Entry. */
+#define ASC_MC_CAM_MODE_MASK            0x015E /* CAM mode TID bitmask. */
+#define ASC_MC_ICQ                      0x0160
+#define ASC_MC_IRQ                      0x0164
 
 /*
  * BIOS LRAM variable absolute offsets.
@@ -2650,7 +2809,6 @@ typedef struct adveep_config
 #define BIOS_CODELEN    0x56
 #define BIOS_SIGNATURE  0x58
 #define BIOS_VERSION    0x5A
-#define BIOS_SIGNATURE  0x58
 
 /*
  * Microcode Control Flags
@@ -2667,50 +2825,61 @@ typedef struct adveep_config
 #define HSHK_CFG_RATE           0x0F00
 #define HSHK_CFG_OFFSET         0x001F
 
-/*
- * LRAM RISC Queue Lists (LRAM addresses 0x1200 - 0x19FF)
- *
- * Each of the 255 Adv Library/Microcode RISC queue lists or mailboxes 
- * starting at LRAM address 0x1200 is 8 bytes and has the following
- * structure. Only 253 of these are actually used for command queues.
- */
-
-#define ASC_MC_RISC_Q_LIST_BASE         0x1200
-#define ASC_MC_RISC_Q_LIST_SIZE         0x0008
-#define ASC_MC_RISC_Q_TOTAL_CNT         0x00FF /* Num. queue slots in LRAM. */
-#define ASC_MC_RISC_Q_FIRST             0x0001
-#define ASC_MC_RISC_Q_LAST              0x00FF
-
 #define ASC_DEF_MAX_HOST_QNG    0xFD /* Max. number of host commands (253) */
 #define ASC_DEF_MIN_HOST_QNG    0x10 /* Min. number of host commands (16) */
 #define ASC_DEF_MAX_DVC_QNG     0x3F /* Max. number commands per device (63) */
 #define ASC_DEF_MIN_DVC_QNG     0x04 /* Min. number commands per device (4) */
 
-/* RISC Queue List structure - 8 bytes */
-#define RQL_FWD     0     /* forward pointer (1 byte) */
-#define RQL_BWD     1     /* backward pointer (1 byte) */
-#define RQL_STATE   2     /* state byte - free, ready, done, aborted (1 byte) */
-#define RQL_TID     3     /* request target id (1 byte) */
-#define RQL_PHYADDR 4     /* request physical pointer (4 bytes) */
-     
-/* RISC Queue List state values */
-#define ASC_MC_QS_FREE                  0x00
-#define ASC_MC_QS_READY                 0x01
-#define ASC_MC_QS_DONE                  0x40
-#define ASC_MC_QS_ABORTED               0x80
+#define ASC_QC_DATA_CHECK  0x01 /* Require ASC_QC_DATA_OUT set or clear. */
+#define ASC_QC_DATA_OUT    0x02 /* Data out DMA transfer. */
+#define ASC_QC_START_MOTOR 0x04 /* Send auto-start motor before request. */
+#define ASC_QC_NO_OVERRUN  0x08 /* Don't report overrun. */
+#define ASC_QC_FREEZE_TIDQ 0x10 /* Freeze TID queue after request. XXX TBD */
+
+#define ASC_QSC_NO_DISC     0x01 /* Don't allow disconnect for request. */
+#define ASC_QSC_NO_TAGMSG   0x02 /* Don't allow tag queuing for request. */
+#define ASC_QSC_NO_SYNC     0x04 /* Don't use Synch. transfer on request. */
+#define ASC_QSC_NO_WIDE     0x08 /* Don't use Wide transfer on request. */
+#define ASC_QSC_REDO_DTR    0x10 /* Renegotiate WDTR/SDTR before request. */
+/*
+ * Note: If a Tag Message is to be sent and neither ASC_QSC_HEAD_TAG or
+ * ASC_QSC_ORDERED_TAG is set, then a Simple Tag Message (0x20) is used.
+ */
+#define ASC_QSC_HEAD_TAG    0x40 /* Use Head Tag Message (0x21). */
+#define ASC_QSC_ORDERED_TAG 0x80 /* Use Ordered Tag Message (0x22). */
+
+typedef struct adv_carr_t
+{
+    ulong       carr_va;       /* Carrier Virtual Address */
+    ulong       carr_pa;       /* Carrier Physical Address */
+    ulong       areq_vpa;      /* ASC_SCSI_REQ_Q Virtual or Physical Address */
+    /*
+     * next_vpa [31:4]            Carrier Virtual or Physical Next Pointer
+     *
+     * next_vpa [3:1]             Reserved Bits
+     * next_vpa [0]               Done Flag set in Response Queue.
+     */
+    ulong       next_vpa;
+} ADV_CARR_T;
+
+/*
+ * Mask used to eliminate low 4 bits of carrier 'next_vpa' field.
+ */
+#define ASC_NEXT_VPA_MASK       0xFFFFFFF0
 
-/* RISC Queue List pointer values */
-#define ASC_MC_NULL_Q                   0x00            /* NULL_Q == 0   */
-#define ASC_MC_BIOS_Q                   0xFF            /* BIOS_Q = 255  */
+#define ASC_RQ_DONE             0x00000001
+#define ASC_CQ_STOPPER          0x00000000
 
-/* ASC_SCSI_REQ_Q 'cntl' field values */
-#define ASC_MC_QC_START_MOTOR           0x02     /* Issue start motor. */
-#define ASC_MC_QC_NO_OVERRUN            0x04     /* Don't report overrun. */
-#define ASC_MC_QC_FIRST_DMA             0x08     /* Internal microcode flag. */
-#define ASC_MC_QC_ABORTED               0x10     /* Request aborted by host. */
-#define ASC_MC_QC_REQ_SENSE             0x20     /* Auto-Request Sense. */
-#define ASC_MC_QC_DOS_REQ               0x80     /* Request issued by DOS. */
+#define ASC_GET_CARRP(carrp) ((ADV_CARR_T *) ((carrp) & ASC_NEXT_VPA_MASK))
 
+#define ADV_PAGE_SIZE   4096    /* Assume 4KB page size. */
+
+#define ADV_CARRIER_NUM_PAGE_CROSSING \
+    (((ADV_CARRIER_COUNT * sizeof(ADV_CARR_T)) + \
+        (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE)
+
+#define ADV_CARRIER_BUFSIZE \
+    ((ADV_CARRIER_COUNT + ADV_CARRIER_NUM_PAGE_CROSSING) * sizeof(ADV_CARR_T))
 
 /*
  * ASC_SCSI_REQ_Q 'a_flag' definitions
@@ -2720,6 +2889,11 @@ typedef struct adveep_config
  */
 #define ADV_POLL_REQUEST                0x01   /* poll for request completion */
 #define ADV_SCSIQ_DONE                  0x02   /* request done */
+#define ADV_DONT_RETRY                  0x08   /* don't do retry */
+
+#define ADV_CHIP_ASC3550          0x01   /* Ultra-Wide IC */
+#define ADV_CHIP_ASC38C0800       0x02   /* Ultra2-Wide/LVD IC */
+#define ADV_CHIP_ASC38C1600       0x03   /* Ultra3-Wide/LVD2 IC */
 
 /*
  * Adapter temporary configuration structure
@@ -2744,12 +2918,20 @@ typedef struct adv_dvc_cfg {
   ushort pci_slot_info;     /* high byte device/function number */
                             /* bits 7-3 device num., bits 2-0 function num. */
                             /* low byte bus num. */
-  ushort bios_boot_wait;    /* BIOS boot time delay */
   ushort serial1;           /* EEPROM serial number word 1 */
   ushort serial2;           /* EEPROM serial number word 2 */
   ushort serial3;           /* EEPROM serial number word 3 */
 } ADV_DVC_CFG; 
 
+struct adv_dvc_var;
+struct adv_scsi_req_q;
+
+typedef void (* ADV_ISR_CALLBACK)
+    (struct adv_dvc_var *, struct adv_scsi_req_q *);
+
+typedef void (* ADV_ASYNC_CALLBACK)
+    (struct adv_dvc_var *, uchar);
+
 /*
  * Adapter operation variable structure.
  *
@@ -2766,23 +2948,32 @@ typedef struct adv_dvc_var {
   AdvPortAddr iop_base;   /* I/O port address */
   ushort err_code;        /* fatal error code */
   ushort bios_ctrl;       /* BIOS control word, EEPROM word 12 */
-  Ptr2Func isr_callback;  /* pointer to function, called in AdvISR() */
-  Ptr2Func sbreset_callback;  /* pointer to function, called in AdvISR() */
+  ADV_ISR_CALLBACK isr_callback;
+  ADV_ASYNC_CALLBACK async_callback;
   ushort wdtr_able;       /* try WDTR for a device */
   ushort sdtr_able;       /* try SDTR for a device */
   ushort ultra_able;      /* try SDTR Ultra speed for a device */
+  ushort sdtr_speed1;     /* EEPROM SDTR Speed for TID 0-3   */
+  ushort sdtr_speed2;     /* EEPROM SDTR Speed for TID 4-7   */
+  ushort sdtr_speed3;     /* EEPROM SDTR Speed for TID 8-11  */
+  ushort sdtr_speed4;     /* EEPROM SDTR Speed for TID 12-15 */
   ushort tagqng_able;     /* try tagged queuing with a device */
   uchar  max_dvc_qng;     /* maximum number of tagged commands per device */
   ushort start_motor;     /* start motor command allowed */
   uchar  scsi_reset_wait; /* delay in seconds after scsi bus reset */
   uchar  chip_no;         /* should be assigned by caller */
   uchar  max_host_qng;    /* maximum number of Q'ed command allowed */
-  uchar  cur_host_qng;    /* total number of queue command */
   uchar  irq_no;          /* IRQ number */
   ushort no_scam;         /* scam_tolerant of EEPROM */
-  ushort idle_cmd_done;   /* microcode idle command done set by AdvISR() */
   ulong  drv_ptr;         /* driver pointer to private structure */
   uchar  chip_scsi_id;    /* chip SCSI target ID */
+  uchar  chip_type;
+  uchar  bist_err_code;
+  ADV_CARR_T *carrier_buf;
+  ADV_CARR_T *carr_freelist; /* Carrier free list. */
+  ADV_CARR_T *icq_sp;  /* Initiator command queue stopper pointer. */
+  ADV_CARR_T *irq_sp;  /* Initiator response queue stopper pointer. */
+  ushort carr_pending_cnt;    /* Count of pending carriers. */
  /*
   * Note: The following fields will not be used after initialization. The
   * driver may discard the buffer after initialization is done.
@@ -2795,17 +2986,17 @@ typedef struct adv_dvc_var {
 typedef struct asc_sg_block {
     uchar reserved1; 
     uchar reserved2; 
-    uchar first_entry_no;             /* starting entry number */
-    uchar last_entry_no;              /* last entry number */
+    uchar reserved3;
+    uchar sg_cnt;                     /* Valid entries in block. */
     struct asc_sg_block *sg_ptr; /* links to the next sg block */
     struct  {
-        ulong sg_addr;                /* SG element address */
-        ulong sg_count;               /* SG element count */
+        ulong sg_addr;                /* SG element address. */
+        ulong sg_count;               /* SG element count. */
     } sg_list[NO_OF_SG_PER_BLOCK];
 } ADV_SG_BLOCK;
 
 /*
- * ASC_SCSI_REQ_Q - microcode request structure
+ * ADV_SCSI_REQ_Q - microcode request structure
  *
  * All fields in this structure up to byte 60 are used by the microcode.
  * The microcode makes assumptions about the size and ordering of fields
@@ -2814,35 +3005,36 @@ typedef struct asc_sg_block {
  */
 typedef struct adv_scsi_req_q {
     uchar       cntl;           /* Ucode flags and state (ASC_MC_QC_*). */
-    uchar       sg_entry_cnt;   /* SG element count. Zero for no SG. */
+    uchar       reserved;
     uchar       target_id;      /* Device target identifier. */
     uchar       target_lun;     /* Device target logical unit number. */
     ulong       data_addr;      /* Data buffer physical address. */
     ulong       data_cnt;       /* Data count. Ucode sets to residual. */
-    ulong       sense_addr;     /* Sense buffer physical address. */
-    ulong       srb_ptr;        /* Driver request pointer. */
-    uchar       a_flag;         /* Adv Library flag field. */
-    uchar       sense_len;      /* Auto-sense length. Ucode sets to residual. */
+    ulong       sense_addr;
+    ulong       carr_pa;
+    uchar       mflag;
+    uchar       sense_len;
     uchar       cdb_len;        /* SCSI CDB length. */
-    uchar       tag_code;       /* SCSI-2 Tag Queue Code: 00, 20-22. */
+    uchar       scsi_cntl;
     uchar       done_status;    /* Completion status. */
     uchar       scsi_status;    /* SCSI status byte. */
     uchar       host_status;    /* Ucode host status. */
-    uchar       ux_sg_ix;       /* Ucode working SG variable. */
+    uchar       sg_working_ix;
     uchar       cdb[12];        /* SCSI command block. */
     ulong       sg_real_addr;   /* SG list physical address. */
-    struct adv_scsi_req_q *free_scsiq_link;
-    ulong       ux_wk_data_cnt; /* Saved data count at disconnection. */
+    ulong       scsiq_rptr;
+    ulong       sg_working_data_cnt;
     struct adv_scsi_req_q *scsiq_ptr;
-    ADV_SG_BLOCK *sg_list_ptr; /* SG list virtual address. */
+    ulong       carr_va;
     /*
      * End of microcode structure - 60 bytes. The rest of the structure
      * is used by the Adv Library and ignored by the microcode.
      */
-    ulong       vsense_addr;    /* Sense buffer virtual address. */
+    ulong       srb_ptr;
+    ADV_SG_BLOCK *sg_list_ptr; /* SG list virtual address. */
     ulong       vdata_addr;     /* Data buffer virtual address. */
-    uchar       orig_sense_len; /* Original length of sense buffer. */
-} ADV_SCSI_REQ_Q; /* BIOS - 70 bytes, DOS - 76 bytes, W95, WNT - 69 bytes */
+    uchar       a_flag;
+} ADV_SCSI_REQ_Q;
 
 /*
  * Microcode idle loop commands
@@ -2853,7 +3045,12 @@ typedef struct adv_scsi_req_q {
 #define IDLE_CMD_SEND_INT            0x0004
 #define IDLE_CMD_ABORT               0x0008
 #define IDLE_CMD_DEVICE_RESET        0x0010
-#define IDLE_CMD_SCSI_RESET          0x0020
+#define IDLE_CMD_SCSI_RESET_START    0x0020 /* Assert SCSI Bus Reset */
+#define IDLE_CMD_SCSI_RESET_END      0x0040 /* Deassert SCSI Bus Reset */
+#define IDLE_CMD_SCSIREQ             0x0080
+
+#define IDLE_CMD_STATUS_SUCCESS      0x0001
+#define IDLE_CMD_STATUS_FAILURE      0x0002
 
 /*
  * AdvSendIdleCmd() flag definitions.
@@ -2863,8 +3060,17 @@ typedef struct adv_scsi_req_q {
 /*
  * Wait loop time out values.
  */
-#define SCSI_WAIT_10_SEC             10         /* 10 seconds */
-#define SCSI_MS_PER_SEC              1000       /* milliseconds per second */
+#define SCSI_WAIT_10_SEC             10UL    /* 10 seconds */
+#define SCSI_WAIT_100_MSEC           100UL   /* 100 milliseconds */
+#define SCSI_US_PER_MSEC             1000    /* microseconds per millisecond */
+#define SCSI_MS_PER_SEC              1000UL  /* milliseconds per second */
+#define SCSI_MAX_RETRY               10      /* retry count */
+
+#define ADV_ASYNC_RDMA_FAILURE          0x01 /* Fatal RDMA failure. */
+#define ADV_ASYNC_SCSI_BUS_RESET_DET    0x02 /* Detected SCSI Bus Reset. */
+#define ADV_ASYNC_CARRIER_READY_FAILURE 0x03 /* Carrier Ready failure. */
+
+#define ADV_HOST_SCSI_BUS_RESET      0x80 /* Host Initiated SCSI Bus Reset. */
 
 /*
  * Device drivers must define the following functions.
@@ -2886,21 +3092,23 @@ STATIC int     AdvExeScsiQueue(ADV_DVC_VAR *,
 STATIC int     AdvISR(ADV_DVC_VAR *);
 STATIC int     AdvInitGetConfig(ADV_DVC_VAR *);
 STATIC int     AdvInitAsc3550Driver(ADV_DVC_VAR *);
-STATIC int     AdvResetSB(ADV_DVC_VAR *);
+STATIC int     AdvInitAsc38C0800Driver(ADV_DVC_VAR *);
+STATIC int     AdvResetChipAndSB(ADV_DVC_VAR *);
+STATIC int     AdvResetSB(ADV_DVC_VAR *asc_dvc);
 
 /*
  * Internal Adv Library functions.
  */
-STATIC int    AdvSendIdleCmd(ADV_DVC_VAR *, ushort, ulong, int);
-STATIC void   AdvResetChip(ADV_DVC_VAR *);
-STATIC int    AdvSendScsiCmd(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
+STATIC int    AdvSendIdleCmd(ADV_DVC_VAR *, ushort, ulong);
 STATIC void   AdvInquiryHandling(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
-STATIC int    AdvInitFromEEP(ADV_DVC_VAR *);
-STATIC ushort AdvGetEEPConfig(AdvPortAddr, ADVEEP_CONFIG *);
-STATIC void   AdvSetEEPConfig(AdvPortAddr, ADVEEP_CONFIG *);
+STATIC int    AdvInitFrom3550EEP(ADV_DVC_VAR *);
+STATIC int    AdvInitFrom38C0800EEP(ADV_DVC_VAR *);
+STATIC ushort AdvGet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
+STATIC void   AdvSet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
+STATIC ushort AdvGet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
+STATIC void   AdvSet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
 STATIC void   AdvWaitEEPCmd(AdvPortAddr);
 STATIC ushort AdvReadEEPWord(AdvPortAddr, int);
-STATIC void   AdvResetSCSIBus(ADV_DVC_VAR *);
 
 /*
  * PCI Bus Definitions
@@ -2911,20 +3119,16 @@ STATIC void   AdvResetSCSIBus(ADV_DVC_VAR *);
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
 
 /* Read byte from a register. */
-#define AdvReadByteRegister(iop_base, reg_off) \
-     (inp((iop_base) + (reg_off)))
+#define AdvReadByteRegister(iop_base, reg_off) (inp((iop_base) + (reg_off)))
 
 /* Write byte to a register. */
-#define AdvWriteByteRegister(iop_base, reg_off, byte) \
-     (outp((iop_base) + (reg_off), (byte)))
+#define AdvWriteByteRegister(iop_base, reg_off, byte) (outp((iop_base) + (reg_off), (byte)))
 
 /* Read word (2 bytes) from a register. */
-#define AdvReadWordRegister(iop_base, reg_off) \
-     (inpw((iop_base) + (reg_off)))
+#define AdvReadWordRegister(iop_base, reg_off) (inpw((iop_base) + (reg_off)))
 
 /* Write word (2 bytes) to a register. */
-#define AdvWriteWordRegister(iop_base, reg_off, word) \
-     (outpw((iop_base) + (reg_off), (word)))
+#define AdvWriteWordRegister(iop_base, reg_off, word) (outpw((iop_base) + (reg_off), (word)))
 
 /* Read byte from LRAM. */
 #define AdvReadByteLram(iop_base, addr, byte) \
@@ -3060,9 +3264,9 @@ do { \
  *      ADV_TRUE(1) - Queue was successfully aborted.
  *      ADV_FALSE(0) - Queue was not found on the active queue list.
  */
-#define AdvAbortSRB(asc_dvc, srb_ptr) \
-    AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_ABORT, \
-                (ulong) (srb_ptr), 0)
+#define AdvAbortQueue(asc_dvc, scsiq) \
+        AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_ABORT, \
+                       (ulong) (scsiq))
 
 /*
  * Send a Bus Device Reset Message to the specified target ID.
@@ -3077,7 +3281,7 @@ do { \
  */
 #define AdvResetDevice(asc_dvc, target_id) \
         AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_DEVICE_RESET, \
-                    (ulong) (target_id), 0)
+                    (ulong) (target_id))
 
 /*
  * SCSI Wide Type definition.
@@ -3120,22 +3324,25 @@ do { \
 #define QHSTA_M_SXFR_XFR_OFLW       0x12 /* SXFR_STATUS Transfer Overflow */
 #define QHSTA_M_SXFR_XFR_PH_ERR     0x24 /* SXFR_STATUS Transfer Phase Error */
 #define QHSTA_M_SXFR_UNKNOWN_ERROR  0x25 /* SXFR_STATUS Unknown Error */
+#define QHSTA_M_SCSI_BUS_RESET      0x30 /* Request aborted from SBR */
+#define QHSTA_M_SCSI_BUS_RESET_UNSOL 0x31 /* Request aborted from unsol. SBR */
+#define QHSTA_M_BUS_DEVICE_RESET    0x32 /* Request aborted from BDR */
+#define QHSTA_M_DIRECTION_ERR       0x35 /* Data Phase mismatch */
+#define QHSTA_M_DIRECTION_ERR_HUNG  0x36 /* Data Phase mismatch and bus hang */
 #define QHSTA_M_WTM_TIMEOUT         0x41
 #define QHSTA_M_BAD_CMPL_STATUS_IN  0x42
 #define QHSTA_M_NO_AUTO_REQ_SENSE   0x43
 #define QHSTA_M_AUTO_REQ_SENSE_FAIL 0x44
 #define QHSTA_M_INVALID_DEVICE      0x45 /* Bad target ID */
+#define QHSTA_M_FROZEN_TIDQ         0x46 /* TID Queue frozen. */
+#define QHSTA_M_SGBACKUP_ERROR      0x47 /* Scatter-Gather backup error */
 
-typedef int (* ADV_ISR_CALLBACK)
-    (ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
-
-typedef int (* ADV_SBRESET_CALLBACK)
-    (ADV_DVC_VAR *);
 
 /*
  * Default EEPROM Configuration structure defined in a_init.c.
  */
-extern ADVEEP_CONFIG Default_EEPROM_Config;
+extern ADVEEP_3550_CONFIG Default_3550_EEPROM_Config;
+extern ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config;
 
 /*
  * DvcGetPhyAddr() flag arguments
@@ -3145,9 +3352,11 @@ extern ADVEEP_CONFIG Default_EEPROM_Config;
 #define ADV_IS_SENSE_FLAG       0x04 /* 'addr' is sense virtual pointer */
 #define ADV_IS_DATA_FLAG        0x08 /* 'addr' is data virtual pointer */
 #define ADV_IS_SGLIST_FLAG      0x10 /* 'addr' is sglist virtual pointer */
+#define ADV_IS_CARRIER_FLAG     0x20 /* 'addr' is ADV_CARR_T pointer */
 
 /* Return the address that is aligned at the next doubleword >= to 'addr'. */
 #define ADV_DWALIGN(addr)       (((ulong) (addr) + 0x3) & ~0x3)
+#define ADV_16BALIGN(addr)     (((ulong) (addr) + 0xF) & ~0xF)
 
 /*
  * Total contiguous memory needed for driver SG blocks.
@@ -3174,6 +3383,44 @@ Forced Error: Driver must define ADV_MAX_SG_LIST.
 #define ADV_ASSERT(a)
 #endif /* ADV_ASSERT */
 
+typedef struct {
+  uchar peri_dvc_type   : 5;    /* peripheral device type */
+  uchar peri_qualifier  : 3;    /* peripheral qualifier */
+  uchar dvc_type_modifier : 7;  /* device type modifier (for SCSI I) */
+  uchar rmb      : 1;           /* RMB - removable medium bit */
+  uchar ansi_apr_ver : 3;       /* ANSI approved version */
+  uchar ecma_ver : 3;           /* ECMA version */
+  uchar iso_ver  : 2;           /* ISO version */
+  uchar rsp_data_fmt : 4;       /* response data format */
+                                /* 0 SCSI 1 */
+                                /* 1 CCS */
+                                /* 2 SCSI-2 */
+                                /* 3-F reserved */
+  uchar res1     : 2;           /* reserved */
+  uchar TemIOP   : 1;           /* terminate I/O process bit (see 5.6.22) */
+  uchar aenc     : 1;           /* asynch. event notification (processor) */
+  uchar add_len;                /* additional length */
+  uchar res2;                   /* reserved */
+  uchar res3;                   /* reserved */
+  uchar StfRe   : 1;            /* soft reset implemented */
+  uchar CmdQue  : 1;            /* command queuing */
+  uchar res4    : 1;            /* reserved */
+  uchar Linked  : 1;            /* linked command for this logical unit */
+  uchar Sync    : 1;            /* synchronous data transfer */
+  uchar WBus16  : 1;            /* wide bus 16 bit data transfer */
+  uchar WBus32  : 1;            /* wide bus 32 bit data transfer */
+  uchar RelAdr  : 1;            /* relative addressing mode */
+  uchar vendor_id[8];           /* vendor identification */
+  uchar product_id[16];         /* product identification */
+  uchar product_rev_level[4];   /* product revision level */
+  uchar vendor_specific[20];    /* vendor specific */
+  uchar IUS      : 1;           /* information unit supported */
+  uchar QAS      : 1;           /* quick arbitrate supported */
+  uchar Clocking : 2;           /* clocking field */
+  uchar res5     : 4;           /* reserved */
+  uchar res6;                   /* reserved */
+} ADV_SCSI_INQUIRY; /* 58 bytes */
+
 
 /*
  * --- Driver Constants and Macros
@@ -3203,11 +3450,17 @@ Forced Error: Driver must define ADV_MAX_SG_LIST.
  * are not used when the driver is built as a module, cf. linux/init.h.
  */
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,23)
+#define ASC_INITFUNC(type, func)        type func
 #define ASC_INITDATA
 #define ASC_INIT
 #else /* version >= v2.1.23 */
-#define ASC_INITDATA            __initdata
-#define ASC_INIT                __init
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,16)
+#define ASC_INITFUNC(type, func)        __initfunc(type func)
+#else /* version >= v2.3.16 */
+#define ASC_INITFUNC(type, func)        type __init func
+#endif /* version >= v2.3.16 */
+#define ASC_INITDATA                    __initdata
+#define ASC_INIT                        __init
 #endif /* version >= v2.1.23 */
 
 #define ASC_INFO_SIZE           128            /* advansys_info() line size */
@@ -3350,11 +3603,12 @@ typedef Scsi_Cmnd            REQ, *REQP;
 #define PCI_MAX_BUS             0xFF
 #define PCI_IOADDRESS_MASK      0xFFFE
 #define ASC_PCI_VENDORID        0x10CD
-#define ASC_PCI_DEVICE_ID_CNT   4       /* PCI Device ID count. */
+#define ASC_PCI_DEVICE_ID_CNT   5       /* PCI Device ID count. */
 #define ASC_PCI_DEVICE_ID_1100  0x1100
 #define ASC_PCI_DEVICE_ID_1200  0x1200
 #define ASC_PCI_DEVICE_ID_1300  0x1300
-#define ASC_PCI_DEVICE_ID_2300  0x2300
+#define ASC_PCI_DEVICE_ID_2300  0x2300  /* ASC-3550 */
+#define ASC_PCI_DEVICE_ID_2500  0x2500  /* ASC-38C0800 */
 
 /* PCI IO Port Addresses to generate special cycle */
 
@@ -3660,14 +3914,12 @@ typedef struct asc_board {
     ADV_SCSI_BIT_ID_TYPE init_tidmask;          /* Target init./valid mask */
     Scsi_Device          *device[ADV_MAX_TID+1]; /* Mid-Level Scsi Device */
     ushort               reqcnt[ADV_MAX_TID+1]; /* Starvation request count */
-#if ASC_QUEUE_FLOW_CONTROL
-    ushort               nerrcnt[ADV_MAX_TID+1]; /* No error request count */
-#endif /* ASC_QUEUE_FLOW_CONTROL */
     ADV_SCSI_BIT_ID_TYPE queue_full;            /* Queue full mask */
     ushort               queue_full_cnt[ADV_MAX_TID+1]; /* Queue full count */
     union {
-        ASCEEP_CONFIG    asc_eep;               /* Narrow EEPROM config. */
-        ADVEEP_CONFIG    adv_eep;               /* Wide EEPROM config. */
+        ASCEEP_CONFIG         asc_eep;          /* Narrow EEPROM config. */
+        ADVEEP_3550_CONFIG    adv_3550_eep;     /* 3550 EEPROM config. */
+        ADVEEP_38C0800_CONFIG adv_38C0800_eep;  /* 38C0800 EEPROM config. */
     } eep_config;
     ulong                last_reset;            /* Saved last reset time */
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
@@ -3690,6 +3942,7 @@ typedef struct asc_board {
      */
     void                 *ioremap_addr;         /* I/O Memory remap address. */
     ushort               ioport;                /* I/O Port address. */
+    ADV_CARR_T           *orig_carrp;           /* ADV_CARR_T memory block. */
     adv_req_t            *orig_reqp;            /* adv_req_t memory block. */
     adv_req_t            *adv_reqp;             /* Request structures. */
     adv_sgblk_t          *orig_sgblkp;          /* adv_sgblk_t memory block. */
@@ -3808,6 +4061,7 @@ STATIC int asc_ioport[ASC_NUM_IOPORT_PROBE] = { 0, 0, 0, 0 };
  * 16 elements of each structure. v1.3.0 kernels will probably
  * not need any more than this number.
  */
+uchar adv_carr_buf[20 * sizeof(ADV_CARR_T)] = { 0 };
 uchar adv_req_buf[16 * sizeof(adv_req_t)] = { 0 };
 uchar adv_sgblk_buf[16 * sizeof(adv_sgblk_t)] = { 0 };
 #endif /* version >= v1,3,0 */
@@ -3854,6 +4108,7 @@ STATIC int        adv_build_req(asc_board_t *, Scsi_Cmnd *, ADV_SCSI_REQ_Q **);
 STATIC int        adv_get_sglist(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *, Scsi_Cmnd *);
 STATIC void       asc_isr_callback(ASC_DVC_VAR *, ASC_QDONE_INFO *);
 STATIC void       adv_isr_callback(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
+STATIC void       adv_async_callback(ADV_DVC_VAR *, uchar);
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
 #ifdef ASC_CONFIG_PCI
 STATIC int        asc_srch_pci_dev(PCI_DEVICE *);
@@ -3883,7 +4138,7 @@ STATIC int        asc_prt_adv_board_info(struct Scsi_Host *, char *, int);
 STATIC int        asc_prt_line(char *, int, char *fmt, ...);
 #endif /* version >= v1.3.0 */
 
-/* Declaration for Asc Library internal functions reference by driver. */
+/* Declaration for Asc Library internal functions referenced by driver. */
 STATIC int          AscFindSignature(PortAddr);
 STATIC ushort       AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
 
@@ -3940,7 +4195,6 @@ advansys_proc_info(char *buffer, char **start, off_t offset, int length,
                    int hostno, int inout)
 {
 #ifdef CONFIG_PROC_FS
-
     struct Scsi_Host    *shp;
     asc_board_t         *boardp;
     int                 i;
@@ -4150,9 +4404,9 @@ advansys_proc_info(char *buffer, char **start, off_t offset, int length,
 #else /* CONFIG_PROC_FS */
     return 0;
 #endif /* CONFIG_PROC_FS */
-
 }
 #endif /* version >= v1.3.0 */
+
 /*
  * advansys_detect()
  *
@@ -4166,20 +4420,27 @@ advansys_proc_info(char *buffer, char **start, off_t offset, int length,
  * it must not call SCSI mid-level functions including scsi_malloc()
  * and scsi_free().
  */
-int ASC_INIT
+ASC_INITFUNC(
+int,
 advansys_detect(Scsi_Host_Template *tpnt)
+)
 {
     static int          detect_called = ASC_FALSE;
     int                 iop;
     int                 bus;
-    struct Scsi_Host    *shp;
-    asc_board_t         *boardp;
+    struct Scsi_Host    *shp = NULL;
+    asc_board_t         *boardp = NULL;
     ASC_DVC_VAR         *asc_dvc_varp = NULL;
     ADV_DVC_VAR         *adv_dvc_varp = NULL;
     int                 ioport = 0;
     int                 share_irq = FALSE;
+    int                 iolen = 0;
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
 #ifdef ASC_CONFIG_PCI
+    int                 pci_init_search = 0;
+    PCI_DEVICE          pci_device[ASC_NUM_BOARD_SUPPORTED];
+    int                 pci_card_cnt_max = 0;
+    int                 pci_card_cnt = 0;
     PCI_DEVICE          pciDevice;
     PCI_CONFIG_SPACE    pciConfig;
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
@@ -4188,13 +4449,18 @@ advansys_detect(Scsi_Host_Template *tpnt)
 #endif /* ASC_CONFIG_PCI */
 #else /* version >= v2.1.93 */ 
 #ifdef CONFIG_PCI
+    int                 pci_init_search = 0;
+    struct pci_dev      *pci_devicep[ASC_NUM_BOARD_SUPPORTED];
+    int                 pci_card_cnt_max = 0;
+    int                 pci_card_cnt = 0;
     struct pci_dev      *pci_devp = NULL;
     int                 pci_device_id_cnt = 0;
     unsigned int        pci_device_id[ASC_PCI_DEVICE_ID_CNT] = {
                                     ASC_PCI_DEVICE_ID_1100,
                                     ASC_PCI_DEVICE_ID_1200,
                                     ASC_PCI_DEVICE_ID_1300,
-                                    ASC_PCI_DEVICE_ID_2300
+                                    ASC_PCI_DEVICE_ID_2300,
+                                    ASC_PCI_DEVICE_ID_2500
                         };
     unsigned long       pci_memory_address;
 #endif /* CONFIG_PCI */
@@ -4308,10 +4574,10 @@ advansys_detect(Scsi_Host_Template *tpnt)
                                 (AscGetChipVersion(iop, ASC_IS_ISA) &
                                  ASC_CHIP_VER_ISA_BIT) == 0) {
                                  /*
-                                 * Don't clear 'asc_ioport[ioport]'. Try
-                                 * this board again for VL. Increment
-                                 * 'ioport' past this board.
-                                 */
+                                  * Don't clear 'asc_ioport[ioport]'. Try
+                                  * this board again for VL. Increment
+                                  * 'ioport' past this board.
+                                  */
                                  ioport++;
                                  goto ioport_try_again;
                             }
@@ -4330,12 +4596,54 @@ advansys_detect(Scsi_Host_Template *tpnt)
                 iop = AscSearchIOPortAddr(iop, asc_bus[bus]);
                 break;
 
+            case ASC_IS_PCI:
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
 #ifdef ASC_CONFIG_PCI
-            case ASC_IS_PCI:
-                if (asc_srch_pci_dev(&pciDevice) != PCI_DEVICE_FOUND) {
+                if (pci_init_search == 0) {
+                    int i, j;
+
+                    pci_init_search = 1;
+
+                    /* Find all PCI cards. */
+                    while (asc_srch_pci_dev(&pciDevice) == PCI_DEVICE_FOUND) {
+                        pci_device[pci_card_cnt_max++] = pciDevice;
+                    }
+
+                    /*
+                     * Sort PCI cards in ascending order by PCI Bus, Slot,
+                     * and Device Number.
+                     */
+                    for (i = 0; i < pci_card_cnt_max - 1; i++)
+                    {
+                        for (j = i + 1; j < pci_card_cnt_max; j++) {
+                            if ((pci_device[j].busNumber <
+                                 pci_device[i].busNumber) ||
+                                ((pci_device[j].busNumber ==
+                                  pci_device[i].busNumber) &&
+                                  (pci_device[j].slotNumber <
+                                   pci_device[i].slotNumber)) ||
+                                ((pci_device[j].busNumber ==
+                                  pci_device[i].busNumber) &&
+                                  (pci_device[j].slotNumber ==
+                                   pci_device[i].slotNumber) &&
+                                  (pci_device[j].devFunc <
+                                   pci_device[i].devFunc))) {
+                                pciDevice = pci_device[i];
+                                pci_device[i] = pci_device[j];
+                                pci_device[j] = pciDevice;
+                            }
+                        }
+                    }
+
+                    pci_card_cnt = 0;
+                } else {
+                    pci_card_cnt++;
+                }
+
+                if (pci_card_cnt == pci_card_cnt_max) {
                     iop = 0;
                 } else {
+                    pciDevice = pci_device[pci_card_cnt];
                     ASC_DBG2(2,
                         "advansys_detect: slotFound %d, busNumber %d\n",
                         pciDevice.slotFound, pciDevice.busNumber);
@@ -4351,31 +4659,69 @@ advansys_detect(Scsi_Host_Template *tpnt)
 #endif /* ASC_CONFIG_PCI */
 #else /* version >= v2.1.93 */ 
 #ifdef CONFIG_PCI
-            case ASC_IS_PCI:
-                while (pci_device_id_cnt < ASC_PCI_DEVICE_ID_CNT) {
-                    if ((pci_devp = pci_find_device(ASC_PCI_VENDORID,
-                         pci_device_id[pci_device_id_cnt], pci_devp)) == NULL) {
-                        pci_device_id_cnt++;
-                    } else {
-                        break;
+                if (pci_init_search == 0) {
+                    int i, j;
+
+                    pci_init_search = 1;
+
+                    /* Find all PCI cards. */
+                    while (pci_device_id_cnt < ASC_PCI_DEVICE_ID_CNT) {
+                        if ((pci_devp = pci_find_device(ASC_PCI_VENDORID,
+                            pci_device_id[pci_device_id_cnt], pci_devp)) ==
+                            NULL) {
+                            pci_device_id_cnt++;
+                        } else {
+                            pci_devicep[pci_card_cnt_max++] = pci_devp;
+                        }
+                    }
+
+                    /*
+                     * Sort PCI cards in ascending order by PCI Bus, Slot,
+                     * and Device Number.
+                     */
+                    for (i = 0; i < pci_card_cnt_max - 1; i++)
+                    {
+                        for (j = i + 1; j < pci_card_cnt_max; j++) {
+                            if ((pci_devicep[j]->bus->number <
+                                 pci_devicep[i]->bus->number) ||
+                                ((pci_devicep[j]->bus->number ==
+                                  pci_devicep[i]->bus->number) &&
+                                  (pci_devicep[j]->devfn <
+                                   pci_devicep[i]->devfn))) {
+                                pci_devp = pci_devicep[i];
+                                pci_devicep[i] = pci_devicep[j];
+                                pci_devicep[j] = pci_devp;
+                            }
+                        }
                     }
+
+                    pci_card_cnt = 0;
+                } else {
+                    pci_card_cnt++;
                 }
-                if (pci_devp == NULL) {
+
+                if (pci_card_cnt == pci_card_cnt_max) {
                     iop = 0;
                 } else {
+                    pci_devp = pci_devicep[pci_card_cnt];
+
                     ASC_DBG2(2,
                         "advansys_detect: devfn %d, bus number %d\n",
                         pci_devp->devfn, pci_devp->bus->number);
-                    iop = pci_devp->resource[0].start;
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,13)
+                    iop = pci_devp->base_address[0] & PCI_IOADDRESS_MASK;
+#else /* version >= v2.3.13 */ 
+                    iop = pci_devp->resource[1].start & PCI_IOADDRESS_MASK;
+#endif /* version >= v2.3.13 */ 
                     ASC_DBG2(1,
                         "advansys_detect: vendorID %X, deviceID %X\n",
                         pci_devp->vendor, pci_devp->device);
                     ASC_DBG2(2, "advansys_detect: iop %X, irqLine %d\n",
                         iop, pci_devp->irq);
                 }
-                break;
 #endif /* CONFIG_PCI */
 #endif /* version >= v2.1.93 */ 
+                break;
 
             default:
                 ASC_PRINT1("advansys_detect: unknown bus type: %d\n",
@@ -4418,14 +4764,18 @@ advansys_detect(Scsi_Host_Template *tpnt)
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
 #ifdef ASC_CONFIG_PCI
             if (asc_bus[bus] == ASC_IS_PCI &&
-                 pciConfig.deviceID == ASC_PCI_DEVICE_ID_2300) {
+                (pciConfig.deviceID == ASC_PCI_DEVICE_ID_2300 ||
+                 pciConfig.deviceID == ASC_PCI_DEVICE_ID_2500))
+            {
                 boardp->flags |= ASC_IS_WIDE_BOARD;
             }
 #endif /* ASC_CONFIG_PCI */
 #else /* version >= v2.1.93 */ 
 #ifdef CONFIG_PCI
             if (asc_bus[bus] == ASC_IS_PCI &&
-                 pci_devp->device == ASC_PCI_DEVICE_ID_2300) {
+                (pci_devp->device == ASC_PCI_DEVICE_ID_2300 ||
+                 pci_devp->device == ASC_PCI_DEVICE_ID_2500))
+            {
                 boardp->flags |= ASC_IS_WIDE_BOARD;
             }
 #endif /* CONFIG_PCI */
@@ -4445,7 +4795,34 @@ advansys_detect(Scsi_Host_Template *tpnt)
                 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
                 adv_dvc_varp->drv_ptr = (ulong) boardp;
                 adv_dvc_varp->cfg = &boardp->dvc_cfg.adv_dvc_cfg;
-                adv_dvc_varp->isr_callback = (Ptr2Func) adv_isr_callback;
+                adv_dvc_varp->isr_callback = adv_isr_callback;
+                adv_dvc_varp->async_callback = adv_async_callback;
+
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
+#ifdef ASC_CONFIG_PCI
+                if (pciConfig.deviceID == ASC_PCI_DEVICE_ID_2300)
+                {
+                    ASC_DBG(1, "advansys_detect: ASC-3550\n");
+                    adv_dvc_varp->chip_type = ADV_CHIP_ASC3550;
+                } else
+                {
+                    ASC_DBG(1, "advansys_detect: ASC-38C0800\n");
+                    adv_dvc_varp->chip_type = ADV_CHIP_ASC38C0800;
+                }
+#endif /* ASC_CONFIG_PCI */
+#else /* version >= v2.1.93 */ 
+#ifdef CONFIG_PCI
+                if (pci_devp->device == ASC_PCI_DEVICE_ID_2300)
+                {
+                    ASC_DBG(1, "advansys_detect: ASC-3550\n");
+                    adv_dvc_varp->chip_type = ADV_CHIP_ASC3550;
+                } else
+                {
+                    ASC_DBG(1, "advansys_detect: ASC-38C0800\n");
+                    adv_dvc_varp->chip_type = ADV_CHIP_ASC38C0800;
+                }
+#endif /* CONFIG_PCI */
+#endif /* version >= v2.1.93 */ 
 
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
                 adv_dvc_varp->iop_base = iop;
@@ -4461,39 +4838,61 @@ advansys_detect(Scsi_Host_Template *tpnt)
                  * PCI register base address will not cross a page
                  * boundary.
                  */
+                if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+                {
+                    iolen = ADV_3550_IOLEN;
+                } else {
+                    iolen = ADV_38C0800_IOLEN;
+                }
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
 #ifdef ASC_CONFIG_PCI
                 pci_memory_address = pciConfig.baseAddress[1];
+                ASC_DBG1(1, "advansys_detect: pci_memory_address: %lu\n",
+                    pci_memory_address);
                 if ((boardp->ioremap_addr =
                     ioremap(pci_memory_address & PAGE_MASK,
                          PAGE_SIZE)) == 0) {
                    ASC_PRINT3(
 "advansys_detect: board %d: ioremap(%lx, %d) returned NULL\n",
-                   boardp->id, pci_memory_address, ADV_CONDOR_IOLEN);
+                   boardp->id, pci_memory_address, iolen);
                    scsi_unregister(shp);
                    asc_board_count--;
                    continue;
                 }
+                ASC_DBG1(1, "advansys_detect: ioremap_addr: %lx\n",
+                    (ulong) boardp->ioremap_addr);
                 adv_dvc_varp->iop_base = (AdvPortAddr)
                     (boardp->ioremap_addr +
                      (pci_memory_address - (pci_memory_address & PAGE_MASK)));
+                ASC_DBG1(1, "advansys_detect: iop_base: %lx\n",
+                    adv_dvc_varp->iop_base);
 #endif /* ASC_CONFIG_PCI */
 #else /* version >= v2.1.93 */ 
 #ifdef CONFIG_PCI
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,13)
+                pci_memory_address = pci_devp->base_address[1];
+#else /* version >= v2.3.13 */ 
                 pci_memory_address = pci_devp->resource[1].start;
+#endif /* version >= v2.3.13 */ 
+                ASC_DBG1(1, "advansys_detect: pci_memory_address: %lu\n",
+                    pci_memory_address);
                 if ((boardp->ioremap_addr =
                     ioremap(pci_memory_address & PAGE_MASK,
                          PAGE_SIZE)) == 0) {
                    ASC_PRINT3(
 "advansys_detect: board %d: ioremap(%lx, %d) returned NULL\n",
-                   boardp->id, pci_memory_address, ADV_CONDOR_IOLEN);
+                   boardp->id, pci_memory_address, iolen);
                    scsi_unregister(shp);
                    asc_board_count--;
                    continue;
                 }
+                ASC_DBG1(1, "advansys_detect: ioremap_addr: %lx\n",
+                    (ulong) boardp->ioremap_addr);
                 adv_dvc_varp->iop_base = (AdvPortAddr)
                     (boardp->ioremap_addr +
                      (pci_memory_address - (pci_memory_address & PAGE_MASK)));
+                ASC_DBG1(1, "advansys_detect: iop_base: %lx\n",
+                    adv_dvc_varp->iop_base);
 #endif /* CONFIG_PCI */
 #endif /* version >= v2.1.93 */ 
 #endif /* version >= v1,3,0 */
@@ -4505,6 +4904,9 @@ advansys_detect(Scsi_Host_Template *tpnt)
                  * displayed.
                  */
                 boardp->ioport = iop;
+
+                ASC_DBG2(1, "iopb_chip_id_1 %x, iopw_chip_id_0 %x\n",
+                    (ushort) inp(iop + 1), (ushort) inpw(iop));
             }
 
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
@@ -4586,9 +4988,9 @@ advansys_detect(Scsi_Host_Template *tpnt)
                 shp->irq = adv_dvc_varp->irq_no = pciConfig.irqLine;
                 adv_dvc_varp->cfg->pci_device_id = pciConfig.deviceID;
                 adv_dvc_varp->cfg->pci_slot_info =
-                ASC_PCI_MKID(pciDevice.busNumber,
-                    pciDevice.slotFound,
-                    pciDevice.devFunc);
+                    ASC_PCI_MKID(pciDevice.busNumber,
+                        pciDevice.slotFound,
+                        pciDevice.devFunc);
                 shp->unchecked_isa_dma = FALSE;
                 share_irq = TRUE;
 #endif /* ASC_CONFIG_PCI */
@@ -4597,9 +4999,9 @@ advansys_detect(Scsi_Host_Template *tpnt)
                 shp->irq = adv_dvc_varp->irq_no = pci_devp->irq;
                 adv_dvc_varp->cfg->pci_device_id = pci_devp->device;
                 adv_dvc_varp->cfg->pci_slot_info =
-                ASC_PCI_MKID(pci_devp->bus->number,
-                    PCI_SLOT(pci_devp->devfn),
-                    PCI_FUNC(pci_devp->devfn));
+                    ASC_PCI_MKID(pci_devp->bus->number,
+                        PCI_SLOT(pci_devp->devfn),
+                        PCI_FUNC(pci_devp->devfn));
                 shp->unchecked_isa_dma = FALSE;
                 share_irq = TRUE;
 #endif /* CONFIG_PCI */
@@ -4616,7 +5018,7 @@ advansys_detect(Scsi_Host_Template *tpnt)
                   * longer be used. If the bus_type field must be
                   * referenced only use the bit-wise AND operator "&".
                   */
-                 ASC_DBG(2, "advansys_detect: AscInitGetConfig()\n");
+                ASC_DBG(2, "advansys_detect: AscInitGetConfig()\n");
                 switch(ret = AscInitGetConfig(asc_dvc_varp)) {
                 case 0:    /* No error */
                     break;
@@ -4776,30 +5178,62 @@ advansys_detect(Scsi_Host_Template *tpnt)
                     shp->irq = asc_dvc_varp->irq_no;
                 }
             } else {
-
-                ADVEEP_CONFIG *ep;
+                ADVEEP_3550_CONFIG      *ep_3550;
+                ADVEEP_38C0800_CONFIG   *ep_38C0800;
 
                 /*
                  * Save Wide EEP Configuration Information.
                  */
-                ep = &boardp->eep_config.adv_eep;
-
-                ep->adapter_scsi_id = adv_dvc_varp->chip_scsi_id;
-                ep->max_host_qng = adv_dvc_varp->max_host_qng;
-                ep->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
-                ep->termination = adv_dvc_varp->cfg->termination;
-                ep->disc_enable = adv_dvc_varp->cfg->disc_enable;
-                ep->bios_ctrl = adv_dvc_varp->bios_ctrl;
-                ep->wdtr_able = adv_dvc_varp->wdtr_able;
-                ep->sdtr_able = adv_dvc_varp->sdtr_able;
-                ep->ultra_able = adv_dvc_varp->ultra_able;
-                ep->tagqng_able = adv_dvc_varp->tagqng_able;
-                ep->start_motor = adv_dvc_varp->start_motor;
-                ep->scsi_reset_delay = adv_dvc_varp->scsi_reset_wait;
-                ep->bios_boot_delay = adv_dvc_varp->cfg->bios_boot_wait;
-                ep->serial_number_word1 = adv_dvc_varp->cfg->serial1;
-                ep->serial_number_word2 = adv_dvc_varp->cfg->serial2;
-                ep->serial_number_word3 = adv_dvc_varp->cfg->serial3;
+                if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+                {
+                    ep_3550 = &boardp->eep_config.adv_3550_eep;
+
+                    ep_3550->adapter_scsi_id = adv_dvc_varp->chip_scsi_id;
+                    ep_3550->max_host_qng = adv_dvc_varp->max_host_qng;
+                    ep_3550->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
+                    ep_3550->termination = adv_dvc_varp->cfg->termination;
+                    ep_3550->disc_enable = adv_dvc_varp->cfg->disc_enable;
+                    ep_3550->bios_ctrl = adv_dvc_varp->bios_ctrl;
+                    ep_3550->wdtr_able = adv_dvc_varp->wdtr_able;
+                    ep_3550->sdtr_able = adv_dvc_varp->sdtr_able;
+                    ep_3550->ultra_able = adv_dvc_varp->ultra_able;
+                    ep_3550->tagqng_able = adv_dvc_varp->tagqng_able;
+                    ep_3550->start_motor = adv_dvc_varp->start_motor;
+                    ep_3550->scsi_reset_delay = adv_dvc_varp->scsi_reset_wait;
+                    ep_3550->serial_number_word1 =
+                        adv_dvc_varp->cfg->serial1;
+                    ep_3550->serial_number_word2 =
+                        adv_dvc_varp->cfg->serial2;
+                    ep_3550->serial_number_word3 =
+                        adv_dvc_varp->cfg->serial3;
+                } else
+                {
+                    ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
+
+                    ep_38C0800->adapter_scsi_id = adv_dvc_varp->chip_scsi_id;
+                    ep_38C0800->max_host_qng = adv_dvc_varp->max_host_qng;
+                    ep_38C0800->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
+                    ep_38C0800->termination_lvd =
+                        adv_dvc_varp->cfg->termination;
+                    ep_38C0800->disc_enable = adv_dvc_varp->cfg->disc_enable;
+                    ep_38C0800->bios_ctrl = adv_dvc_varp->bios_ctrl;
+                    ep_38C0800->wdtr_able = adv_dvc_varp->wdtr_able;
+                    ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
+                    ep_38C0800->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
+                    ep_38C0800->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
+                    ep_38C0800->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
+                    ep_38C0800->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
+                    ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
+                    ep_38C0800->start_motor = adv_dvc_varp->start_motor;
+                    ep_38C0800->scsi_reset_delay =
+                        adv_dvc_varp->scsi_reset_wait;
+                    ep_38C0800->serial_number_word1 =
+                        adv_dvc_varp->cfg->serial1;
+                    ep_38C0800->serial_number_word2 =
+                        adv_dvc_varp->cfg->serial2;
+                    ep_38C0800->serial_number_word3 =
+                        adv_dvc_varp->cfg->serial3;
+                }
 
                 /*
                  * Set the adapter's target id bit in the 'init_tidmask' field.
@@ -4842,7 +5276,7 @@ advansys_detect(Scsi_Host_Template *tpnt)
                  * Memory Mapped I/O.
                  */
                 shp->io_port = iop;
-                shp->n_io_port = ADV_CONDOR_IOLEN;
+                shp->n_io_port = iolen;
 
                 shp->this_id = adv_dvc_varp->chip_scsi_id;
 
@@ -5065,17 +5499,30 @@ advansys_detect(Scsi_Host_Template *tpnt)
                         warn_code, err_code);
                 }
             } else {
+                ADV_CARR_T      *carrp;
                 int             req_cnt;
                 adv_req_t       *reqp = NULL;
-                int             sg_cnt;
+                int             sg_cnt = 0;
                 adv_sgblk_t     *sgp = NULL;
 
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
+                carrp = (ADV_CARR_T *) &adv_carr_buf[0];
                 req_cnt = sizeof(adv_req_buf)/sizeof(adv_req_t);
                 sg_cnt = sizeof(adv_sgblk_buf)/sizeof(adv_sgblk_t);
                 reqp = (adv_req_t *) &adv_req_buf[0];
                 sgp = (adv_sgblk_t *) &adv_sgblk_buf[0];
 #else /* version >= v1.3.0 */
+                /*
+                 * Allocate buffer carrier structures.
+                 */
+                carrp =
+                    (ADV_CARR_T *) kmalloc(ADV_CARRIER_BUFSIZE, GFP_ATOMIC);
+                ASC_DBG1(1, "advansys_detect: carrp %x\n", (unsigned) carrp);
+
+                if (carrp == NULL) {
+                    goto kmalloc_error;
+                }
+
                 /*
                  * Allocate up to 'max_host_qng' request structures for
                  * the Wide board.
@@ -5094,6 +5541,10 @@ advansys_detect(Scsi_Host_Template *tpnt)
                         break;
                     }
                 }
+                if (reqp == NULL)
+                {
+                    goto kmalloc_error;
+                }
 
                 /*
                  * Allocate up to ADV_TOT_SG_LIST request structures for
@@ -5112,19 +5563,27 @@ advansys_detect(Scsi_Host_Template *tpnt)
                         break;
                     }
                 }
-#endif /* version >= v1.3.0 */
 
                 /*
                  * If no request structures or scatter-gather structures could
                  * be allocated, then return an error. Otherwise continue with
                  * initialization.
                  */
-                if (reqp == NULL) {
+    kmalloc_error:
+                if (carrp == NULL)
+                {
+                    ASC_PRINT1(
+"advansys_detect: board %d: error: failed to kmalloc() carrier buffer.\n",
+                        boardp->id);
+                    err_code = ADV_ERROR;
+                } else if (reqp == NULL) {
+                    kfree(carrp);
                     ASC_PRINT1(
 "advansys_detect: board %d: error: failed to kmalloc() adv_req_t buffer.\n",
                         boardp->id);
                     err_code = ADV_ERROR;
                 } else if (sgp == NULL) {
+                    kfree(carrp);
                     kfree(reqp);
                     ASC_PRINT1(
 "advansys_detect: board %d: error: failed to kmalloc() adv_sgblk_t buffer.\n",
@@ -5132,12 +5591,24 @@ advansys_detect(Scsi_Host_Template *tpnt)
                     err_code = ADV_ERROR;
                 } else {
                     
+                    /* Save carrier buffer pointer. */
+                    boardp->orig_carrp = carrp;
+
                     /*
                      * Save original pointer for kfree() in case the
                      * driver is built as a module and can be unloaded.
                      */
                     boardp->orig_reqp = reqp;
 
+                    /*
+                     * Save original pointer for kfree() in case the
+                     * driver is built as a module and can be unloaded.
+                     */
+                    boardp->orig_sgblkp = sgp;
+#endif /* version >= v1.3.0 */
+
+                    adv_dvc_varp->carrier_buf = carrp;
+
                     /*
                      * Point 'adv_reqp' to the request structures and
                      * link them together.
@@ -5149,12 +5620,6 @@ advansys_detect(Scsi_Host_Template *tpnt)
                     }
                     boardp->adv_reqp = &reqp[0];
 
-                    /*
-                     * Save original pointer for kfree() in case the
-                     * driver is built as a module and can be unloaded.
-                     */
-                    boardp->orig_sgblkp = sgp;
-
                     /*
                      * Point 'adv_sgblkp' to the request structures and
                      * link them together.
@@ -5166,24 +5631,37 @@ advansys_detect(Scsi_Host_Template *tpnt)
                     }
                     boardp->adv_sgblkp = &sgp[0];
 
-                    ASC_DBG(2, "advansys_detect: AdvInitAsc3550Driver()\n");
-                    warn_code = AdvInitAsc3550Driver(adv_dvc_varp);
+                    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+                    {
+                        ASC_DBG(2,
+                            "advansys_detect: AdvInitAsc3550Driver()\n");
+                        warn_code = AdvInitAsc3550Driver(adv_dvc_varp);
+                    } else {
+                        ASC_DBG(2,
+                            "advansys_detect: AdvInitAsc38C0800Driver()\n");
+                        warn_code = AdvInitAsc38C0800Driver(adv_dvc_varp);
+                    }
                     err_code = adv_dvc_varp->err_code;
 
                     if (warn_code || err_code) {
                         ASC_PRINT3(
-"AdvInitAsc3550Driver: board %d: error: warn %x, error %x\n",
+"AdvInitAsc3550/38C0800Driver: board %d: error: warn %x, error %x\n",
                             boardp->id, warn_code, adv_dvc_varp->err_code);
                     }
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
                 }
+#endif /* version >= v1,3,0 */
             }
 
             if (err_code != 0) {
                 release_region(shp->io_port, shp->n_io_port);
-                if (ASC_WIDE_BOARD(boardp)) {
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
+                if (ASC_WIDE_BOARD(boardp)) {
                     iounmap(boardp->ioremap_addr);
-#endif /* version >= v1,3,0 */
+                    if (boardp->orig_carrp) {
+                        kfree(boardp->orig_carrp);
+                        boardp->orig_carrp = NULL;
+                    }
                     if (boardp->orig_reqp) {
                         kfree(boardp->orig_reqp);
                         boardp->orig_reqp = boardp->adv_reqp = NULL;
@@ -5193,6 +5671,7 @@ advansys_detect(Scsi_Host_Template *tpnt)
                         boardp->orig_sgblkp = boardp->adv_sgblkp = NULL;
                     }
                 }
+#endif /* version >= v1,3,0 */
                 if (shp->dma_channel != NO_ISA_DMA) {
                     free_dma(shp->dma_channel);
                 }
@@ -5237,10 +5716,13 @@ advansys_release(struct Scsi_Host *shp)
         free_dma(shp->dma_channel);
     }
     release_region(shp->io_port, shp->n_io_port);
-    if (ASC_WIDE_BOARD(boardp)) {
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
+    if (ASC_WIDE_BOARD(boardp)) {
         iounmap(boardp->ioremap_addr);
-#endif /* version >= v1,3,0 */
+        if (boardp->orig_carrp) {
+            kfree(boardp->orig_carrp);
+            boardp->orig_carrp = NULL;
+        }
         if (boardp->orig_reqp) {
             kfree(boardp->orig_reqp);
             boardp->orig_reqp = boardp->adv_reqp = NULL;
@@ -5250,7 +5732,6 @@ advansys_release(struct Scsi_Host *shp)
             boardp->orig_sgblkp = boardp->adv_sgblkp = NULL;
         }
     }
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
     ASC_ASSERT(boardp->prtbuf != NULL);
     kfree(boardp->prtbuf);
 #endif /* version >= v1.3.0 */
@@ -5276,6 +5757,8 @@ advansys_info(struct Scsi_Host *shp)
     ASC_DVC_VAR     *asc_dvc_varp;
     ADV_DVC_VAR     *adv_dvc_varp;
     char            *busname;
+    int             iolen;
+    char            *widename = NULL;
 
     boardp = ASC_BOARDP(shp);
     if (ASC_NARROW_BOARD(boardp)) {
@@ -5342,21 +5825,31 @@ advansys_info(struct Scsi_Host *shp)
          * I/O address is displayed through the driver /proc file.
          */
         adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
+        if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+        {
+            iolen = ADV_3550_IOLEN;
+            widename = "Ultra-Wide";
+        } else {
+            iolen = ADV_38C0800_IOLEN;
+            widename = "Ultra2-Wide";
+        }
         if (boardp->bios_signature == 0x55AA) {
             sprintf(info,
-"AdvanSys SCSI %s: PCI Ultra-Wide: BIOS %X/%X, IO %X/%X, IRQ %u",
+"AdvanSys SCSI %s: PCI %s: BIOS %X/%X, IO %X/%X, IRQ %u",
                 ASC_VERSION,
+                widename,
                 boardp->bios_codeseg << 4,
                 boardp->bios_codelen > 0 ?
                 (boardp->bios_codelen << 9) - 1 : 0,
-                (unsigned) boardp->ioport, ADV_CONDOR_IOLEN - 1,
+                (unsigned) boardp->ioport, iolen - 1,
                 shp->irq);
         } else {
             sprintf(info,
-"AdvanSys SCSI %s: PCI Ultra-Wide: IO %X/%X, IRQ %u",
+"AdvanSys SCSI %s: PCI %s: IO %X/%X, IRQ %u",
                 ASC_VERSION,
+                widename,
                 (unsigned) boardp->ioport,
-                (ADV_CONDOR_IOLEN - 1),
+                (iolen - 1),
                 shp->irq);
         }
     }
@@ -5579,7 +6072,7 @@ advansys_abort(Scsi_Cmnd *scp)
                 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
                 scp->result = HOST_BYTE(DID_ABORT);
 
-                /* sti(); - FIXME!!! Enable interrupts for AscAbortSRB() must be careful about io_lock. */
+                /* sti(); XXX */ /* Enable interrupts for AscAbortSRB(). */
                 ASC_DBG1(1, "advansys_abort: before AscAbortSRB(), scp %x\n",
                     (unsigned) scp);
                 switch (AscAbortSRB(asc_dvc_varp, (ulong) scp)) {
@@ -5607,22 +6100,23 @@ advansys_abort(Scsi_Cmnd *scp)
                 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
                 scp->result = HOST_BYTE(DID_ABORT);
 
-                ASC_DBG1(1, "advansys_abort: before AdvAbortSRB(), scp %x\n",
+                ASC_DBG1(1, "advansys_abort: before AdvAbortQueue(), scp %x\n",
                     (unsigned) scp);
-                switch (AdvAbortSRB(adv_dvc_varp, (ulong) scp)) {
+#if 0 /* XXX */
+                switch (AdvAbortQueue(adv_dvc_varp, (ulong) XXX)) {
                 case ASC_TRUE:
                     /* asc_isr_callback() will be called */
-                    ASC_DBG(1, "advansys_abort: AdvAbortSRB() TRUE\n");
+                    ASC_DBG(1, "advansys_abort: AdvAbortQueue() TRUE\n");
                     ret = SCSI_ABORT_PENDING;
                     break;
                 case ASC_FALSE:
                     /* Request has apparently already completed. */
-                    ASC_DBG(1, "advansys_abort: AdvAbortSRB() FALSE\n");
+                    ASC_DBG(1, "advansys_abort: AdvAbortQueue() FALSE\n");
                     ret = SCSI_ABORT_NOT_RUNNING;
                     break;
                 case ASC_ERROR:
                 default:
-                    ASC_DBG(1, "advansys_abort: AdvAbortSRB() ERROR\n");
+                    ASC_DBG(1, "advansys_abort: AdvAbortQueue() ERROR\n");
                     ret = SCSI_ABORT_ERROR;
                     break;
                 }
@@ -5631,6 +6125,10 @@ advansys_abort(Scsi_Cmnd *scp)
                  * been processed by calling AdvISR().
                  */
                 (void) AdvISR(adv_dvc_varp);
+#else /* XXX */
+                (void) AdvResetChipAndSB(adv_dvc_varp);
+                ret = SCSI_ABORT_SUCCESS;
+#endif /* XXX */
             }
 
             /*
@@ -5644,7 +6142,6 @@ advansys_abort(Scsi_Cmnd *scp)
                 scp_found = asc_rmqueue(&boardp->done, scp);
                 ASC_ASSERT(scp_found == ASC_TRUE);
             }
-
         } else {
             /*
              * The command was not found on the active or waiting queues.
@@ -5786,8 +6283,13 @@ advansys_reset(Scsi_Cmnd *scp, unsigned int reset_flags)
         }
         scp->result = HOST_BYTE(DID_ERROR);
         ret = SCSI_RESET_ERROR;
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,0)
     } else if (time_after_eq(jiffies, boardp->last_reset) &&
                time_before(jiffies, boardp->last_reset + (10 * HZ))) {
+#else /* version < v2.1.0 */
+    } else if (jiffies >= boardp->last_reset &&
+               jiffies < (boardp->last_reset + (10 * HZ))) {
+#endif /* version < v2.1.0 */
         /*
          * Don't allow a reset to be attempted within 10 seconds
          * of the last reset.
@@ -5849,9 +6351,9 @@ advansys_reset(Scsi_Cmnd *scp, unsigned int reset_flags)
                  * Reset the target's SCSI bus.
                  */
                 ASC_DBG(1, "advansys_reset: before AscResetSB()\n");
-                /* sti();    FIXME!!! Enable interrupts for AscResetSB(). */
+                /* sti(); XXX */ /* Enable interrupts for AscResetSB(). */
                 status = AscResetSB(asc_dvc_varp);
-                /* cli();    FIXME!!! */
+                /* cli(); XXX */
                 switch (status) {
                 case ASC_TRUE:
                     ASC_DBG(1, "advansys_reset: AscResetSB() success\n");
@@ -5874,9 +6376,9 @@ advansys_reset(Scsi_Cmnd *scp, unsigned int reset_flags)
                 ASC_DBG1(1,
                     "advansys_reset: before AscResetDevice(), target %d\n",
                     scp->target);
-                /* sti();    FIXME!!! Enable interrupts for AscResetDevice(). */
+                /* sti(); XXX */ /* Enable interrupts for AscResetDevice(). */
                 status = AscResetDevice(asc_dvc_varp, scp->target);
-                /* cli();    FIXME!!! */
+                /* cli(); XXX */
 
                 switch (status) {
                 case ASC_TRUE:
@@ -5888,9 +6390,9 @@ advansys_reset(Scsi_Cmnd *scp, unsigned int reset_flags)
                 default:
                     ASC_DBG(1,
 "advansys_reset: AscResetDevice() failed; Calling AscResetSB()\n");
-                    /* sti();   FIXME!!! Enable interrupts for AscResetSB(). */
+                    /* sti(); XXX */ /* Enable interrupts for AscResetSB(). */
                     status = AscResetSB(asc_dvc_varp);
-                    /* cli(); */
+                    /* cli(); XXX */
                     switch (status) {
                     case ASC_TRUE:
                         ASC_DBG(1, "advansys_reset: AscResetSB() TRUE\n");
@@ -5923,15 +6425,16 @@ advansys_reset(Scsi_Cmnd *scp, unsigned int reset_flags)
                 /*
                  * Reset the target's SCSI bus.
                  */
-                ASC_DBG(1, "advansys_reset: before AdvResetSB()\n");
-                switch (AdvResetSB(adv_dvc_varp)) {
+                ASC_DBG(1, "advansys_reset: before AdvResetChipAndSB()\n");
+                switch (AdvResetChipAndSB(adv_dvc_varp)) {
                 case ASC_TRUE:
-                    ASC_DBG(1, "advansys_reset: AdvResetSB() success\n");
+                    ASC_DBG(1,
+                        "advansys_reset: AdvResetChipAndSB() success\n");
                     ret = SCSI_RESET_SUCCESS;
                     break;
                 case ASC_FALSE:
                 default:
-                    ASC_DBG(1, "advansys_reset: AdvResetSB() failed\n");
+                    ASC_DBG(1, "advansys_reset: AdvResetChipAndSB() failed\n");
                     ret = SCSI_RESET_ERROR;
                     break;
                 }
@@ -5960,16 +6463,18 @@ advansys_reset(Scsi_Cmnd *scp, unsigned int reset_flags)
                 case ASC_FALSE:
                 default:
                     ASC_DBG(1,
-"advansys_reset: AdvResetDevice() failed; Calling AdvResetSB()\n");
+"advansys_reset: AdvResetDevice() failed; Calling AdvResetChipAndSB()\n");
                     
-                    switch (AdvResetSB(adv_dvc_varp)) {
+                    switch (AdvResetChipAndSB(adv_dvc_varp)) {
                     case ASC_TRUE:
-                        ASC_DBG(1, "advansys_reset: AdvResetSB() TRUE\n");
+                        ASC_DBG(1,
+                            "advansys_reset: AdvResetChipAndSB() TRUE\n");
                         ret = SCSI_RESET_SUCCESS;
                         break;
                     case ASC_FALSE:
                     default:
-                        ASC_DBG(1, "advansys_reset: AdvResetSB() ERROR\n");
+                        ASC_DBG(1,
+                            "advansys_reset: AdvResetChipAndSB() ERROR\n");
                         ret = SCSI_RESET_ERROR;
                         break;
                     }
@@ -6188,8 +6693,10 @@ advansys_biosparam(Disk *dp, kdev_t dep, int ip[])
  * ints[2] - second argument
  * ...
  */
-void ASC_INIT
+ASC_INITFUNC(
+void,
 advansys_setup(char *str, int *ints)
+)
 {
     int    i;
 
@@ -6541,27 +7048,6 @@ asc_execute_scsi_cmnd(Scsi_Cmnd *scp)
              */
             boardp->reqcnt[scp->target]++;
 
-#if ASC_QUEUE_FLOW_CONTROL
-            /*
-             * Conditionally increment the device queue depth.
-             *
-             * If no error occurred and there have been 100 consecutive
-             * successful requests and the current queue depth is less
-             * than the maximum queue depth, then increment the current
-             * queue depth.
-             */
-            if (boardp->nerrcnt[scp->target]++ > 100) {
-                boardp->nerrcnt[scp->target] = 0;
-                if (device != NULL &&
-                    (device->queue_curr_depth < device->queue_depth) &&
-                    (!(boardp->queue_full &
-                       ADV_TID_TO_TIDMASK(scp->target)) ||
-                     (boardp->queue_full_cnt[scp->target] >
-                      device->queue_curr_depth))) {
-                    device->queue_curr_depth++;
-                }
-            }
-#endif /* ASC_QUEUE_FLOW_CONTROL */
             asc_enqueue(&boardp->active, scp, ASC_BACK);
             ASC_DBG(1,
                 "asc_execute_scsi_cmnd: AscExeScsiQueue(), ASC_NOERROR\n");
@@ -6569,26 +7055,12 @@ asc_execute_scsi_cmnd(Scsi_Cmnd *scp)
         case ASC_BUSY:
             /* Caller must enqueue request and retry later. */
             ASC_STATS(scp->host, exe_busy);
-#if ASC_QUEUE_FLOW_CONTROL
-            /*
-             * Clear consecutive no error counter and if possible decrement
-             * queue depth.
-             */
-            boardp->nerrcnt[scp->target] = 0;
-            if (device != NULL && device->queue_curr_depth > 1) {
-                device->queue_curr_depth--;
-            }
-#endif /* ASC_QUEUE_FLOW_CONTROL */
             break;
         case ASC_ERROR:
             ASC_PRINT2(
 "asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() ASC_ERROR, err_code %x\n",
                 boardp->id, asc_dvc_varp->err_code);
             ASC_STATS(scp->host, exe_error);
-#if ASC_QUEUE_FLOW_CONTROL
-            /* Clear consecutive no error counter. */
-            boardp->nerrcnt[scp->target] = 0;
-#endif /* ASC_QUEUE_FLOW_CONTROL */
             scp->result = HOST_BYTE(DID_ERROR);
             asc_enqueue(&boardp->done, scp, ASC_BACK);
             break;
@@ -6597,10 +7069,6 @@ asc_execute_scsi_cmnd(Scsi_Cmnd *scp)
 "asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() unknown, err_code %x\n",
                 boardp->id, asc_dvc_varp->err_code);
             ASC_STATS(scp->host, exe_unknown);
-#if ASC_QUEUE_FLOW_CONTROL
-            /* Clear consecutive no error counter. */
-            boardp->nerrcnt[scp->target] = 0;
-#endif /* ASC_QUEUE_FLOW_CONTROL */
             scp->result = HOST_BYTE(DID_ERROR);
             asc_enqueue(&boardp->done, scp, ASC_BACK);
             break;
@@ -6868,7 +7336,6 @@ adv_build_req(asc_board_t *boardp, Scsi_Cmnd *scp,
     scsiqp->target_id = scp->target;
     scsiqp->target_lun = scp->lun;
 
-    scsiqp->vsense_addr = (ulong) &scp->sense_buffer[0];
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
     scsiqp->sense_addr = (ulong) &scp->sense_buffer[0];
 #else /* version >= v2.0.0 */
@@ -6994,7 +7461,7 @@ adv_get_sglist(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp,
     ADV_SG_BLOCK        *sg_block;              /* virtual address of a SG */
     ulong               sg_block_next_addr;     /* block and its next */
     ulong               sg_block_physical_addr;
-    int                 sg_block_index, i;      /* how many SG entries */
+    int                 i;
     struct scatterlist  *slp;
     int                 sg_elem_cnt;
 
@@ -7013,10 +7480,8 @@ adv_get_sglist(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp,
                    sg_block_physical_addr);
     scsiqp->sg_real_addr = sg_block_physical_addr;
 
-    sg_block_index = 0;
     do
     {
-        sg_block->first_entry_no = sg_block_index;
         for (i = 0; i < NO_OF_SG_PER_BLOCK; i++)
         {
             sg_block->sg_list[i].sg_addr =
@@ -7030,21 +7495,19 @@ adv_get_sglist(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp,
 
             if (--sg_elem_cnt == 0)
             {   /* last entry, get out */
-                scsiqp->sg_entry_cnt = sg_block_index + i + 1;
-                sg_block->last_entry_no = sg_block_index + i;
+                sg_block->sg_cnt = i + 1;
                 sg_block->sg_ptr = 0L;    /* next link = NULL */
                 return ADV_SUCCESS;
             }
             slp++;
         } 
+        sg_block->sg_cnt = NO_OF_SG_PER_BLOCK;
         sg_block_next_addr += sizeof(ADV_SG_BLOCK);
         sg_block_physical_addr += sizeof(ADV_SG_BLOCK);
         ADV_ASSERT(ADV_DWALIGN(sg_block_physical_addr) ==
                        sg_block_physical_addr);
 
-        sg_block_index += NO_OF_SG_PER_BLOCK;
         sg_block->sg_ptr = (ADV_SG_BLOCK *) sg_block_physical_addr;
-        sg_block->last_entry_no = sg_block_index - 1;
         sg_block = (ADV_SG_BLOCK *) sg_block_next_addr; /* virtual addr */
     }
     while (1);
@@ -7270,7 +7733,7 @@ adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp)
      * command that has been completed.
      *
      * Note: The adv_req_t request structure and adv_sgblk_t structure,
-     * if any, * dropped, because a board structure pointer can not be
+     * if any, are dropped, because a board structure pointer can not be
      * determined.
      */
     scp = reqp->cmndp;
@@ -7443,13 +7906,53 @@ adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp)
     return;
 }
 
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
-#ifdef ASC_CONFIG_PCI
+/*
+ * adv_async_callback() - Adv Library asynchronous event callback function.
+ */
+STATIC void
+adv_async_callback(ADV_DVC_VAR *adv_dvc_varp, uchar code)
+{
+    switch (code)
+    {
+    case ADV_ASYNC_SCSI_BUS_RESET_DET:
+        /*
+         * The firmware detected a SCSI Bus reset.
+         */
+        ASC_DBG(0, "adv_async_callback: ADV_ASYNC_SCSI_BUS_RESET_DET\n");
+        break;
+
+    case ADV_ASYNC_RDMA_FAILURE:
+        /*
+         * Handle RDMA failure by resetting the SCSI Bus and
+         * possibly the chip if it is unresponsive. Log the error
+         * with a unique code.
+         */
+        ASC_DBG(0, "adv_async_callback: ADV_ASYNC_RDMA_FAILURE\n");
+        AdvResetChipAndSB(adv_dvc_varp);
+        break;
+
+    case ADV_HOST_SCSI_BUS_RESET:
+        /*
+         * Host generated SCSI bus reset occurred.
+         */
+        ASC_DBG(0, "adv_async_callback: ADV_HOST_SCSI_BUS_RESET\n");
+        break;
+
+    default:
+        ASC_DBG1(0, "DvcAsyncCallBack: unknown code 0x%x\n", code);
+        break;
+    }
+}
+
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
+#ifdef ASC_CONFIG_PCI
 /*
  * Search for an AdvanSys PCI device in the PCI configuration space.
  */
-STATIC int ASC_INIT
+ASC_INITFUNC(
+STATIC int,
 asc_srch_pci_dev(PCI_DEVICE *pciDevice)
+)
 {
     int                        ret = PCI_DEVICE_NOT_FOUND;
 
@@ -7486,8 +7989,10 @@ asc_srch_pci_dev(PCI_DEVICE *pciDevice)
 /*
  * Determine the access method to be used for 'pciDevice'.
  */
-STATIC uchar ASC_INIT
+ASC_INITFUNC(
+STATIC uchar,
 asc_scan_method(void)
+)
 {
     ushort      data;
     PCI_DATA    pciData;
@@ -7516,8 +8021,10 @@ asc_scan_method(void)
  *
  * Return PCI_DEVICE_FOUND if found, otherwise return PCI_DEVICE_NOT_FOUND.
  */
-STATIC int ASC_INIT
+ASC_INITFUNC(
+STATIC int,
 asc_pci_find_dev(PCI_DEVICE *pciDevice)
+)
 {
     PCI_DATA    pciData;
     ushort      vendorid, deviceid;
@@ -7542,7 +8049,8 @@ asc_pci_find_dev(PCI_DEVICE *pciDevice)
                 ((deviceid == ASC_PCI_DEVICE_ID_1100) ||
                  (deviceid == ASC_PCI_DEVICE_ID_1200) ||
                  (deviceid == ASC_PCI_DEVICE_ID_1300) ||
-                 (deviceid == ASC_PCI_DEVICE_ID_2300))) {
+                 (deviceid == ASC_PCI_DEVICE_ID_2300) ||
+                 (deviceid == ASC_PCI_DEVICE_ID_2500))) {
                 pciDevice->slotFound = lslot;
                 ASC_DBG(3, "asc_pci_find_dev: PCI_DEVICE_FOUND\n");
                 return PCI_DEVICE_FOUND;
@@ -7566,8 +8074,10 @@ asc_pci_find_dev(PCI_DEVICE *pciDevice)
 /*
  * Read PCI configuration data into 'pciConfig'.
  */
-STATIC void ASC_INIT
+ASC_INITFUNC(
+STATIC void,
 asc_get_pci_cfg(PCI_DEVICE *pciDevice, PCI_CONFIG_SPACE *pciConfig)
+)
 {
     PCI_DATA    pciData;
     uchar       counter;
@@ -7596,8 +8106,10 @@ asc_get_pci_cfg(PCI_DEVICE *pciDevice, PCI_CONFIG_SPACE *pciConfig)
  *
  * The configuration mechanism is checked for the correct access method.
  */
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
 asc_get_cfg_word(PCI_DATA *pciData)
+)
 {
     ushort   tmp;
     ulong    address;
@@ -7626,7 +8138,7 @@ asc_get_cfg_word(PCI_DATA *pciData)
         /* set for type 1 cycle, if needed */
         outp(0xCFA, pciData->bus);
         /* set the function number */
-        outp(0xCF8, 0x10 | (pciData->func << 1)) ;
+        outp(0xCF8, 0x10 | (pciData->func << 1));
 
         /*
          * Read the configuration space type 2 locations.
@@ -7677,8 +8189,10 @@ asc_get_cfg_word(PCI_DATA *pciData)
  *
  * The configuration mechanism is checked for the correct access method.
  */
-STATIC uchar ASC_INIT
+ASC_INITFUNC(
+STATIC uchar,
 asc_get_cfg_byte(PCI_DATA *pciData)
+)
 {
     uchar tmp;
     ulong address;
@@ -7755,8 +8269,10 @@ asc_get_cfg_byte(PCI_DATA *pciData)
 /*
  * Write a byte to the PCI configuration space.
  */
-STATIC void ASC_INIT
+ASC_INITFUNC(
+STATIC void,
 asc_put_cfg_byte(PCI_DATA *pciData, uchar byte_data)
+)
 {
     ulong tmpl;
     ulong address;
@@ -8498,19 +9014,29 @@ asc_prt_asc_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen)
 STATIC int
 asc_prt_adv_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen)
 {
-    asc_board_t        *boardp;
-    ADV_DVC_VAR        *adv_dvc_varp;
-    int                leftlen;
-    int                totlen;
-    int                len;
-    int                i;
-    char               *termstr;
-    uchar              serialstr[13];
-    ADVEEP_CONFIG      *ep;
+    asc_board_t                 *boardp;
+    ADV_DVC_VAR                 *adv_dvc_varp;
+    int                         leftlen;
+    int                         totlen;
+    int                         len;
+    int                         i;
+    char                        *termstr;
+    uchar                       serialstr[13];
+    ADVEEP_3550_CONFIG          *ep_3550 = NULL;
+    ADVEEP_38C0800_CONFIG       *ep_38C0800 = NULL;
+    ushort                      word;
+    ushort                      *wordp;
+    ushort                      sdtr_speed = 0;
 
     boardp = ASC_BOARDP(shp);
     adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
-    ep = &boardp->eep_config.adv_eep;
+    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+    {
+        ep_3550 = &boardp->eep_config.adv_3550_eep;
+    } else
+    {
+        ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
+    }
 
     leftlen = cplen;
     totlen = len = 0;
@@ -8519,8 +9045,15 @@ asc_prt_adv_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen)
 "\nEEPROM Settings for AdvanSys SCSI Host %d:\n", shp->host_no);
     ASC_PRT_NEXT();
 
-    if (asc_get_eeprom_string(&ep->serial_number_word1, serialstr) ==
-        ASC_TRUE) {
+    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+    {
+        wordp = &ep_3550->serial_number_word1;
+    } else
+    {
+        wordp = &ep_38C0800->serial_number_word1;
+    }
+
+    if (asc_get_eeprom_string(wordp, serialstr) == ASC_TRUE) {
         len = asc_prt_line(cp, leftlen, " Serial Number: %s\n", serialstr);
         ASC_PRT_NEXT();
     } else {
@@ -8529,12 +9062,29 @@ asc_prt_adv_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen)
         ASC_PRT_NEXT();
     }
 
-    len = asc_prt_line(cp, leftlen,
+    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+    {
+        len = asc_prt_line(cp, leftlen,
 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
-        ep->adapter_scsi_id, ep->max_host_qng, ep->max_dvc_qng);
-    ASC_PRT_NEXT();
-
-    switch (ep->termination) {
+            ep_3550->adapter_scsi_id, ep_3550->max_host_qng,
+            ep_3550->max_dvc_qng);
+        ASC_PRT_NEXT();
+    } else
+    {
+        len = asc_prt_line(cp, leftlen,
+" Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
+            ep_38C0800->adapter_scsi_id, ep_38C0800->max_host_qng,
+            ep_38C0800->max_dvc_qng);
+        ASC_PRT_NEXT();
+    }
+    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+    {
+        word = ep_3550->termination;
+    } else
+    {
+        word = ep_38C0800->termination_lvd;
+    }
+    switch (word) {
         case 1:
             termstr = "Low Off/High Off";
             break;
@@ -8550,10 +9100,19 @@ asc_prt_adv_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen)
             break;
     }
 
-    len = asc_prt_line(cp, leftlen,
+    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+    {
+        len = asc_prt_line(cp, leftlen,
 " termination: %u (%s), bios_ctrl: %x\n",
-        ep->termination, termstr, ep->bios_ctrl);
-    ASC_PRT_NEXT();
+            ep_3550->termination, termstr, ep_3550->bios_ctrl);
+        ASC_PRT_NEXT();
+    } else
+    {
+        len = asc_prt_line(cp, leftlen,
+" termination: %u (%s), bios_ctrl: %x\n",
+            ep_38C0800->termination_lvd, termstr, ep_38C0800->bios_ctrl);
+        ASC_PRT_NEXT();
+    }
 
     len = asc_prt_line(cp, leftlen,
 " Target ID:           ");
@@ -8565,72 +9124,150 @@ asc_prt_adv_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen)
     len = asc_prt_line(cp, leftlen, "\n");
     ASC_PRT_NEXT();
 
+    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+    {
+        word = ep_3550->disc_enable;
+    } else
+    {
+        word = ep_38C0800->disc_enable;
+    }
     len = asc_prt_line(cp, leftlen,
 " Disconnects:         ");
     ASC_PRT_NEXT();
     for (i = 0; i <= ADV_MAX_TID; i++) {
         len = asc_prt_line(cp, leftlen, " %c",
-            (ep->disc_enable & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+            (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
         ASC_PRT_NEXT();
     }
     len = asc_prt_line(cp, leftlen, "\n");
     ASC_PRT_NEXT();
 
+    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+    {
+        word = ep_3550->tagqng_able;
+    } else
+    {
+        word = ep_38C0800->tagqng_able;
+    }
     len = asc_prt_line(cp, leftlen,
 " Command Queuing:     ");
     ASC_PRT_NEXT();
     for (i = 0; i <= ADV_MAX_TID; i++) {
         len = asc_prt_line(cp, leftlen, " %c",
-            (ep->tagqng_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+            (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
         ASC_PRT_NEXT();
     }
     len = asc_prt_line(cp, leftlen, "\n");
     ASC_PRT_NEXT();
 
+    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+    {
+        word = ep_3550->start_motor;
+    } else
+    {
+        word = ep_38C0800->start_motor;
+    }
     len = asc_prt_line(cp, leftlen,
 " Start Motor:         ");
     ASC_PRT_NEXT();
     for (i = 0; i <= ADV_MAX_TID; i++) {
         len = asc_prt_line(cp, leftlen, " %c",
-            (ep->start_motor & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+            (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
         ASC_PRT_NEXT();
     }
     len = asc_prt_line(cp, leftlen, "\n");
     ASC_PRT_NEXT();
 
-    len = asc_prt_line(cp, leftlen,
+    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+    {
+        len = asc_prt_line(cp, leftlen,
 " Synchronous Transfer:");
-    ASC_PRT_NEXT();
-    for (i = 0; i <= ADV_MAX_TID; i++) {
-        len = asc_prt_line(cp, leftlen, " %c",
-            (ep->sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+        ASC_PRT_NEXT();
+        for (i = 0; i <= ADV_MAX_TID; i++) {
+            len = asc_prt_line(cp, leftlen, " %c",
+                (ep_3550->sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+            ASC_PRT_NEXT();
+        }
+        len = asc_prt_line(cp, leftlen, "\n");
         ASC_PRT_NEXT();
     }
-    len = asc_prt_line(cp, leftlen, "\n");
-    ASC_PRT_NEXT();
 
-    len = asc_prt_line(cp, leftlen,
+    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+    {
+        len = asc_prt_line(cp, leftlen,
 " Ultra Transfer:      ");
     ASC_PRT_NEXT();
-    for (i = 0; i <= ADV_MAX_TID; i++) {
-        len = asc_prt_line(cp, leftlen, " %c",
-            (ep->ultra_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+        for (i = 0; i <= ADV_MAX_TID; i++) {
+            len = asc_prt_line(cp, leftlen, " %c",
+                (ep_3550->ultra_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+            ASC_PRT_NEXT();
+        }
+        len = asc_prt_line(cp, leftlen, "\n");
         ASC_PRT_NEXT();
     }
-    len = asc_prt_line(cp, leftlen, "\n");
-    ASC_PRT_NEXT();
 
+    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+    {
+        word = ep_3550->wdtr_able;
+    } else
+    {
+        word = ep_38C0800->wdtr_able;
+    }
     len = asc_prt_line(cp, leftlen,
 " Wide Transfer:       ");
     ASC_PRT_NEXT();
     for (i = 0; i <= ADV_MAX_TID; i++) {
         len = asc_prt_line(cp, leftlen, " %c",
-            (ep->wdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+            (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
         ASC_PRT_NEXT();
     }
     len = asc_prt_line(cp, leftlen, "\n");
     ASC_PRT_NEXT();
 
+    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
+    {
+        len = asc_prt_line(cp, leftlen,
+" Synchronous Transfer Speed (Mhz):\n  ");
+        ASC_PRT_NEXT();
+        for (i = 0; i <= ADV_MAX_TID; i++) {
+            char *speed_str;
+
+            if (i == 0)
+            {
+                sdtr_speed = adv_dvc_varp->sdtr_speed1;
+            } else if (i == 4)
+            {
+                sdtr_speed = adv_dvc_varp->sdtr_speed2;
+            } else if (i == 8)
+            {
+                sdtr_speed = adv_dvc_varp->sdtr_speed3;
+            } else if (i == 12)
+            {
+                sdtr_speed = adv_dvc_varp->sdtr_speed4;
+            }
+            switch (sdtr_speed & ADV_MAX_TID)
+            {
+                case 0:  speed_str = "Off"; break;
+                case 1:  speed_str = "  5"; break;
+                case 2:  speed_str = " 10"; break;
+                case 3:  speed_str = " 20"; break;
+                case 4:  speed_str = " 40"; break;
+                case 5:  speed_str = " 80"; break;
+                default: speed_str = "Unk"; break;
+            }
+            len = asc_prt_line(cp, leftlen, "%X:%s ", i, speed_str);
+            ASC_PRT_NEXT();
+            if (i == 7)
+            {
+                len = asc_prt_line(cp, leftlen, "\n  ");
+                ASC_PRT_NEXT();
+            }
+            sdtr_speed >>= 4;
+        }
+        len = asc_prt_line(cp, leftlen, "\n");
+        ASC_PRT_NEXT();
+    }
+
     return totlen;
 }
 
@@ -8728,46 +9365,6 @@ asc_prt_driver_conf(struct Scsi_Host *shp, char *cp, int cplen)
     }
 #endif /* version >= v1.3.89 */
 
-#if ASC_QUEUE_FLOW_CONTROL
-    if (ASC_NARROW_BOARD(boardp)) {
-        len = asc_prt_line(cp, leftlen, " queue_curr_depth:");
-        ASC_PRT_NEXT();
-        /* Use ASC_MAX_TID for Narrow Board. */
-        for (i = 0; i <= ASC_MAX_TID; i++) {
-            if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
-                ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
-                continue;
-            }
-            if (boardp->device[i] == NULL) {
-                continue;
-            }
-            len = asc_prt_line(cp, leftlen, " %d:%d",
-                i, boardp->device[i]->queue_curr_depth);
-            ASC_PRT_NEXT();
-        }
-        len = asc_prt_line(cp, leftlen, "\n");
-        ASC_PRT_NEXT();
-
-        len = asc_prt_line(cp, leftlen, " queue_count:");
-        ASC_PRT_NEXT();
-        /* Use ASC_MAX_TID for Narrow Board. */
-        for (i = 0; i <= ASC_MAX_TID; i++) {
-            if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
-                ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
-                continue;
-            }
-            if (boardp->device[i] == NULL) {
-                continue;
-            }
-            len = asc_prt_line(cp, leftlen, " %d:%d",
-                i, boardp->device[i]->queue_count);
-            ASC_PRT_NEXT();
-        }
-        len = asc_prt_line(cp, leftlen, "\n");
-        ASC_PRT_NEXT();
-    }
-#endif /* ASC_QUEUE_FLOW_CONTROL */
-
     return totlen;
 }
 
@@ -8786,16 +9383,19 @@ STATIC int
 asc_prt_asc_board_info(struct Scsi_Host *shp, char *cp, int cplen)
 {
     asc_board_t            *boardp;
+    int                    chip_scsi_id;
     int                    leftlen;
     int                    totlen;
     int                    len;
     ASC_DVC_VAR            *v;
     ASC_DVC_CFG            *c;
     int                    i;
+    int                    renegotiate = 0;
 
     boardp = ASC_BOARDP(shp);
     v = &boardp->dvc_var.asc_dvc_var;
     c = &boardp->dvc_cfg.asc_dvc_cfg;
+    chip_scsi_id = c->chip_scsi_id;
 
     leftlen = cplen;
     totlen = len = 0;
@@ -8824,11 +9424,11 @@ asc_prt_asc_board_info(struct Scsi_Host *shp, char *cp, int cplen)
 " Command Queuing:");
     ASC_PRT_NEXT();
     for (i = 0; i <= ASC_MAX_TID; i++) {
-        if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) ||
+        if ((chip_scsi_id == i) ||
             ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
             continue;
         }
-        len = asc_prt_line(cp, leftlen, " %d:%c",
+        len = asc_prt_line(cp, leftlen, " %X:%c",
             i, (v->use_tagged_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
         ASC_PRT_NEXT();
     }
@@ -8840,11 +9440,11 @@ asc_prt_asc_board_info(struct Scsi_Host *shp, char *cp, int cplen)
 " Command Queue Pending:");
     ASC_PRT_NEXT();
     for (i = 0; i <= ASC_MAX_TID; i++) {
-        if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) ||
+        if ((chip_scsi_id == i) ||
             ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
             continue;
         }
-        len = asc_prt_line(cp, leftlen, " %d:%u", i, v->cur_dvc_qng[i]);
+        len = asc_prt_line(cp, leftlen, " %X:%u", i, v->cur_dvc_qng[i]);
         ASC_PRT_NEXT();
     }
     len = asc_prt_line(cp, leftlen, "\n");
@@ -8855,11 +9455,11 @@ asc_prt_asc_board_info(struct Scsi_Host *shp, char *cp, int cplen)
 " Command Queue Limit:");
     ASC_PRT_NEXT();
     for (i = 0; i <= ASC_MAX_TID; i++) {
-        if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) ||
+        if ((chip_scsi_id == i) ||
             ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
             continue;
         }
-        len = asc_prt_line(cp, leftlen, " %d:%u", i, v->max_dvc_qng[i]);
+        len = asc_prt_line(cp, leftlen, " %X:%u", i, v->max_dvc_qng[i]);
         ASC_PRT_NEXT();
     }
     len = asc_prt_line(cp, leftlen, "\n");
@@ -8870,15 +9470,15 @@ asc_prt_asc_board_info(struct Scsi_Host *shp, char *cp, int cplen)
 " Command Queue Full:");
     ASC_PRT_NEXT();
     for (i = 0; i <= ASC_MAX_TID; i++) {
-        if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) ||
+        if ((chip_scsi_id == i) ||
             ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
             continue;
         }
         if (boardp->queue_full & ADV_TID_TO_TIDMASK(i)) {
-            len = asc_prt_line(cp, leftlen, " %d:Y-%d",
+            len = asc_prt_line(cp, leftlen, " %X:Y-%d",
                 i, boardp->queue_full_cnt[i]);
         } else {
-            len = asc_prt_line(cp, leftlen, " %d:N", i);
+            len = asc_prt_line(cp, leftlen, " %X:N", i);
         }
         ASC_PRT_NEXT();
     }
@@ -8889,11 +9489,11 @@ asc_prt_asc_board_info(struct Scsi_Host *shp, char *cp, int cplen)
 " Synchronous Transfer:");
     ASC_PRT_NEXT();
     for (i = 0; i <= ASC_MAX_TID; i++) {
-        if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) ||
+        if ((chip_scsi_id == i) ||
             ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
             continue;
         }
-        len = asc_prt_line(cp, leftlen, " %d:%c",
+        len = asc_prt_line(cp, leftlen, " %X:%c",
             i, (v->sdtr_done & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
         ASC_PRT_NEXT();
     }
@@ -8903,26 +9503,50 @@ asc_prt_asc_board_info(struct Scsi_Host *shp, char *cp, int cplen)
     for (i = 0; i <= ASC_MAX_TID; i++) {
         uchar syn_period_ix;
 
-        if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) ||
-            ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+        if ((chip_scsi_id == i) ||
+            ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
+            ((v->init_sdtr & ADV_TID_TO_TIDMASK(i)) == 0)) {
             continue;
         }
+
+        len = asc_prt_line(cp, leftlen, "  %X:", i);
+        ASC_PRT_NEXT();
+
+        if ((boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET) == 0)
+        {
+            len = asc_prt_line(cp, leftlen, " Asynchronous");
+            ASC_PRT_NEXT();
+        } else
+        {
+            syn_period_ix =
+                (boardp->sdtr_data[i] >> 4) & (v->max_sdtr_index - 1);
+
+            len = asc_prt_line(cp, leftlen,
+                " Transfer Period Factor: %d (%d.%d Mhz),",
+                v->sdtr_period_tbl[syn_period_ix],
+                250 / v->sdtr_period_tbl[syn_period_ix],
+                ASC_TENTHS(250, v->sdtr_period_tbl[syn_period_ix]));
+            ASC_PRT_NEXT();
+
+            len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
+                boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET);
+            ASC_PRT_NEXT();
+        }
+
         if ((v->sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
-            continue;
+            len = asc_prt_line(cp, leftlen, "*\n");
+            renegotiate = 1;
+        } else
+        {
+            len = asc_prt_line(cp, leftlen, "\n");
         }
-        syn_period_ix = (boardp->sdtr_data[i] >> 4) & (v->max_sdtr_index - 1);
-        len = asc_prt_line(cp, leftlen, "  %d:", i);
         ASC_PRT_NEXT();
+    }
 
+    if (renegotiate)
+    {
         len = asc_prt_line(cp, leftlen,
-            " Transfer Period Factor: %d (%d.%d Mhz),",
-            v->sdtr_period_tbl[syn_period_ix],
-            250 / v->sdtr_period_tbl[syn_period_ix],
-            ASC_TENTHS(250, v->sdtr_period_tbl[syn_period_ix]));
-        ASC_PRT_NEXT();
-
-        len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d\n",
-            boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET);
+            " * = Re-negotiation pending before next command.\n");
         ASC_PRT_NEXT();
     }
 
@@ -8954,8 +9578,11 @@ asc_prt_adv_board_info(struct Scsi_Host *shp, char *cp, int cplen)
     ushort                 chip_scsi_id;
     ushort                 lramword;
     uchar                  lrambyte;
-    ushort                 sdtr_able;
-    ushort                 period;
+    ushort                 tagqng_able;
+    ushort                 sdtr_able, wdtr_able;
+    ushort                 wdtr_done, sdtr_done;
+    ushort                 period = 0;
+    int                    renegotiate = 0;
 
     boardp = ASC_BOARDP(shp);
     v = &boardp->dvc_var.adv_dvc_var;
@@ -8972,10 +9599,10 @@ asc_prt_adv_board_info(struct Scsi_Host *shp, char *cp, int cplen)
     ASC_PRT_NEXT();
 
     len = asc_prt_line(cp, leftlen,
-" iop_base %lx, cable_detect: %X, err_code %u, idle_cmd_done %u\n",
+" iop_base %lx, cable_detect: %X, err_code %u\n",
          v->iop_base,
          AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1) & CABLE_DETECT,
-         v->err_code, v->idle_cmd_done);
+         v->err_code);
     ASC_PRT_NEXT();
 
     len = asc_prt_line(cp, leftlen,
@@ -8983,7 +9610,7 @@ asc_prt_adv_board_info(struct Scsi_Host *shp, char *cp, int cplen)
         c->chip_version, c->lib_version, c->mcode_date, c->mcode_version);
     ASC_PRT_NEXT();
 
-    AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, lramword);
+    AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
     len = asc_prt_line(cp, leftlen,
 " Queuing Enabled:");
     ASC_PRT_NEXT();
@@ -8994,7 +9621,7 @@ asc_prt_adv_board_info(struct Scsi_Host *shp, char *cp, int cplen)
         }
 
         len = asc_prt_line(cp, leftlen, " %X:%c",
-            i, (lramword & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+            i, (tagqng_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
         ASC_PRT_NEXT();
     }
     len = asc_prt_line(cp, leftlen, "\n");
@@ -9034,7 +9661,7 @@ asc_prt_adv_board_info(struct Scsi_Host *shp, char *cp, int cplen)
     len = asc_prt_line(cp, leftlen, "\n");
     ASC_PRT_NEXT();
 
-    AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, lramword);
+    AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
     len = asc_prt_line(cp, leftlen,
 " Wide Enabled:");
     ASC_PRT_NEXT();
@@ -9045,12 +9672,13 @@ asc_prt_adv_board_info(struct Scsi_Host *shp, char *cp, int cplen)
         }
 
         len = asc_prt_line(cp, leftlen, " %X:%c",
-            i, (lramword & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+            i, (wdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
         ASC_PRT_NEXT();
     }
     len = asc_prt_line(cp, leftlen, "\n");
     ASC_PRT_NEXT();
 
+    AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, wdtr_done);
     len = asc_prt_line(cp, leftlen,
 " Transfer Bit Width:");
     ASC_PRT_NEXT();
@@ -9062,9 +9690,17 @@ asc_prt_adv_board_info(struct Scsi_Host *shp, char *cp, int cplen)
 
         AdvReadWordLram(iop_base, ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
             lramword);
+
         len = asc_prt_line(cp, leftlen, " %X:%d",
             i, (lramword & 0x8000) ? 16 : 8);
         ASC_PRT_NEXT();
+
+        if ((wdtr_able & ADV_TID_TO_TIDMASK(i)) &&
+            (wdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
+            len = asc_prt_line(cp, leftlen, "*");
+            ASC_PRT_NEXT();
+            renegotiate = 1;
+        }
     }
     len = asc_prt_line(cp, leftlen, "\n");
     ASC_PRT_NEXT();
@@ -9086,6 +9722,7 @@ asc_prt_adv_board_info(struct Scsi_Host *shp, char *cp, int cplen)
     len = asc_prt_line(cp, leftlen, "\n");
     ASC_PRT_NEXT();
 
+    AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, sdtr_done);
     for (i = 0; i <= ADV_MAX_TID; i++) {
 
         AdvReadWordLram(iop_base, ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
@@ -9093,23 +9730,67 @@ asc_prt_adv_board_info(struct Scsi_Host *shp, char *cp, int cplen)
         lramword &= ~0x8000;
 
         if ((chip_scsi_id == i) ||
-            ((sdtr_able & ADV_TID_TO_TIDMASK(i)) == 0) ||
-            (lramword == 0)) {
+            ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
+            ((sdtr_able & ADV_TID_TO_TIDMASK(i)) == 0)) {
             continue;
         }
 
         len = asc_prt_line(cp, leftlen, "  %X:", i);
         ASC_PRT_NEXT();
-        
-        period = (((lramword >> 8) * 25) + 50)/4;
 
-        len = asc_prt_line(cp, leftlen,
-            " Transfer Period Factor: %d (%d.%d Mhz),",
-            period, 250/period, ASC_TENTHS(250, period));
+        if ((lramword & 0x1F) == 0) /* Check for REQ/ACK Offset 0. */
+        {
+            len = asc_prt_line(cp, leftlen, " Asynchronous");
+            ASC_PRT_NEXT();
+        } else
+        {
+            len = asc_prt_line(cp, leftlen, " Transfer Period Factor: ");
+            ASC_PRT_NEXT();
+
+            if ((lramword & 0x1F00) == 0x1100) /* 80 Mhz */
+            {
+                len = asc_prt_line(cp, leftlen, "9 (80.0 Mhz),");
+                ASC_PRT_NEXT();
+            } else if ((lramword & 0x1F00) == 0x1000) /* 40 Mhz */
+            {
+                len = asc_prt_line(cp, leftlen, "10 (40.0 Mhz),");
+                ASC_PRT_NEXT();
+            } else /* 20 Mhz or below. */
+            {
+                period = (((lramword >> 8) * 25) + 50)/4;
+
+                if (period == 0) /* Should never happen. */
+                {
+                    len = asc_prt_line(cp, leftlen, "%d (? Mhz), ");
+                    ASC_PRT_NEXT();
+                } else
+                {
+                    len = asc_prt_line(cp, leftlen,
+                        "%d (%d.%d Mhz),",
+                        period, 250/period, ASC_TENTHS(250, period));
+                    ASC_PRT_NEXT();
+                }
+            }
+
+            len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
+                lramword & 0x1F);
+            ASC_PRT_NEXT();
+        }
+
+        if ((sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
+            len = asc_prt_line(cp, leftlen, "*\n");
+            renegotiate = 1;
+        } else
+        {
+            len = asc_prt_line(cp, leftlen, "\n");
+        }
         ASC_PRT_NEXT();
+    }
 
-        len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d\n",
-            lramword & 0x1F);
+    if (renegotiate)
+    {
+        len = asc_prt_line(cp, leftlen,
+            " * = Re-negotiation pending before next command.\n");
         ASC_PRT_NEXT();
     }
 
@@ -9164,7 +9845,7 @@ asc_prt_line(char *buf, int buflen, char *fmt, ...)
 {
     va_list        args;
     int            ret;
-    char        s[ASC_PRTLINE_SIZE];
+    char           s[ASC_PRTLINE_SIZE];
 
     va_start(args, fmt);
     ret = vsprintf(s, fmt, args);
@@ -9195,8 +9876,18 @@ asc_prt_line(char *buf, int buflen, char *fmt, ...)
 STATIC void
 DvcSleepMilliSecond(ulong n)
 {
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0)
+    ulong i;
+#endif /* version < v2.1.0 */ 
+
     ASC_DBG1(4, "DvcSleepMilliSecond: %lu\n", n);
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,0)
     mdelay(n);
+#else /* version < v2.1.0 */ 
+    for (i = 0; i < n; i++) {
+        udelay(1000);
+    }
+#endif /* version < v2.1.0 */ 
 }
 
 STATIC int
@@ -9346,10 +10037,12 @@ DvcOutPortDWords(PortAddr port, ulong *pdw, int dwords)
 /*
  * Read a PCI configuration byte.
  */
-STATIC uchar ASC_INIT
+ASC_INITFUNC(
+STATIC uchar,
 DvcReadPCIConfigByte(
         ASC_DVC_VAR asc_ptr_type *asc_dvc, 
         ushort offset)
+)
 {
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
 #ifdef ASC_CONFIG_PCI
@@ -9381,11 +10074,13 @@ DvcReadPCIConfigByte(
 /*
  * Write a PCI configuration byte.
  */
-STATIC void ASC_INIT
+ASC_INITFUNC(
+STATIC void,
 DvcWritePCIConfigByte(
         ASC_DVC_VAR asc_ptr_type *asc_dvc, 
         ushort offset, 
         uchar  byte_data)
+)
 {
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
 #ifdef ASC_CONFIG_PCI
@@ -9412,14 +10107,16 @@ DvcWritePCIConfigByte(
  * Return the BIOS address of the adapter at the specified
  * I/O port and with the specified bus type.
  */
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
 AscGetChipBiosAddress(
         PortAddr iop_base,
         ushort bus_type
 )
+)
 {
-    ushort  cfg_lsw ;
-    ushort  bios_addr ;
+    ushort  cfg_lsw;
+    ushort  bios_addr;
 
     /*
      * The PCI BIOS is re-located by the motherboard BIOS. Because
@@ -9433,14 +10130,14 @@ AscGetChipBiosAddress(
 
     if((bus_type & ASC_IS_EISA) != 0)
     {
-        cfg_lsw = AscGetEisaChipCfg(iop_base) ;
-        cfg_lsw &= 0x000F ;
+        cfg_lsw = AscGetEisaChipCfg(iop_base);
+        cfg_lsw &= 0x000F;
         bios_addr = (ushort)(ASC_BIOS_MIN_ADDR  +
-                                (cfg_lsw * ASC_BIOS_BANK_SIZE)) ;
-        return(bios_addr) ;
+                                (cfg_lsw * ASC_BIOS_BANK_SIZE));
+        return(bios_addr);
     }/* if */
 
-    cfg_lsw = AscGetChipCfgLsw(iop_base) ;
+    cfg_lsw = AscGetChipCfgLsw(iop_base);
 
     /*
     *  ISA PnP uses the top bit as the 32K BIOS flag
@@ -9451,8 +10148,8 @@ AscGetChipBiosAddress(
     }/* if */
 
     bios_addr = (ushort)(((cfg_lsw >> 12) * ASC_BIOS_BANK_SIZE) +
-            ASC_BIOS_MIN_ADDR) ;
-    return(bios_addr) ;
+            ASC_BIOS_MIN_ADDR);
+    return(bios_addr);
 }
 
 
@@ -9493,10 +10190,12 @@ DvcGetPhyAddr(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq,
 /*
  * Read a PCI configuration byte.
  */
-STATIC uchar ASC_INIT
+ASC_INITFUNC(
+STATIC uchar,
 DvcAdvReadPCIConfigByte(
         ADV_DVC_VAR *asc_dvc, 
         ushort offset)
+)
 {
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
 #ifdef ASC_CONFIG_PCI
@@ -9528,11 +10227,13 @@ DvcAdvReadPCIConfigByte(
 /*
  * Write a PCI configuration byte.
  */
-STATIC void ASC_INIT
+ASC_INITFUNC(
+STATIC void,
 DvcAdvWritePCIConfigByte(
         ADV_DVC_VAR *asc_dvc, 
         ushort offset, 
         uchar  byte_data)
+)
 {
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
 #ifdef ASC_CONFIG_PCI
@@ -9743,12 +10444,13 @@ asc_prt_scsi_host(struct Scsi_Host *s)
         (unsigned) s->hostt, (unsigned) s->block);
 
     printk(
-" wish_block %d, base %x, io_port %d, n_io_port %d, irq %d, dma_channel %d,\n",
-        s->wish_block, (unsigned) s->base, s->io_port, s->n_io_port,
-        s->irq, s->dma_channel);
+" wish_block %d, base %lu, io_port %lu, n_io_port %u, irq %d,\n",
+        s->wish_block, (ulong) s->base, (ulong) s->io_port, s->n_io_port,
+        s->irq);
 
     printk(
-" this_id %d, can_queue %d,\n", s->this_id, s->can_queue);
+" dma_channel %d, this_id %d, can_queue %d,\n",
+        s->dma_channel, s->this_id, s->can_queue);
 
     printk(
 " cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d, loaded_as_module %d\n",
@@ -9966,15 +10668,23 @@ asc_prt_adv_dvc_var(ADV_DVC_VAR *h)
         (unsigned) h->scsi_reset_wait, (unsigned) h->irq_no);
 
     printk(
-"  max_host_qng 0x%x, cur_host_qng 0x%x, max_dvc_qng 0x%x\n",
-        (unsigned) h->max_host_qng, (unsigned) h->cur_host_qng,
-        (unsigned) h->max_dvc_qng);
+"  max_host_qng %x, max_dvc_qng %x, carr_freelist %lxn\n",
+        (unsigned) h->max_host_qng, (unsigned) h->max_dvc_qng,
+        (ulong) h->carr_freelist);
+
 
     printk(
-"  no_scam 0x%x, tagqng_able 0x%x, chip_scsi_id 0x%x, cfg 0x%lx\n",
-        (unsigned) h->no_scam, (unsigned) h->tagqng_able,
-        (unsigned) h->chip_scsi_id, (ulong) h->cfg);
+"  icq_sp %lx, irq_sp %lx\n",
+        (ulong) h->icq_sp,
+        (ulong) h->irq_sp);
+
+    printk(
+"  no_scam 0x%x, tagqng_able 0x%x\n",
+        (unsigned) h->no_scam, (unsigned) h->tagqng_able);
 
+    printk(
+"  chip_scsi_id 0x%x, cfg %lx\n",
+        (unsigned) h->chip_scsi_id, (ulong) h->cfg);
 }
 
 /*
@@ -10012,7 +10722,7 @@ asc_prt_adv_dvc_cfg(ADV_DVC_CFG *h)
 STATIC void 
 asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q)
 {
-    int                 i;
+    int                 sg_blk_cnt;
     struct asc_sg_block *sg_ptr;
 
     printk("ADV_SCSI_REQ_Q at addr %x\n", (unsigned) q);
@@ -10024,6 +10734,10 @@ asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q)
     printk("  cntl 0x%x, data_addr 0x%lx, vdata_addr 0x%lx\n",
             q->cntl, q->data_addr, q->vdata_addr);
 
+    printk(
+"  cntl 0x%x, data_addr %lx, vdata_addr %lx\n",
+            q->cntl, q->data_addr, q->vdata_addr);
+
     printk(
 "  data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
             q->data_cnt, q->sense_addr, q->sense_len);
@@ -10033,32 +10747,33 @@ asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q)
             q->cdb_len, q->done_status, q->host_status, q->scsi_status);
 
     printk(
-"  vsense_addr 0x%lx, scsiq_ptr 0x%lx, ux_wk_data_cnt %lu\n",
-            (ulong) q->vsense_addr, (ulong) q->scsiq_ptr,
-            (ulong) q->ux_wk_data_cnt);
-
-    printk(
-"  sg_list_ptr 0x%lx, sg_real_addr 0x%lx, sg_entry_cnt %u\n",
-            (ulong) q->sg_list_ptr, (ulong) q->sg_real_addr, q->sg_entry_cnt);
+"  sg_working_ix %x, sg_working_data_cnt %lx, reserved %u\n",
+            q->sg_working_ix, q->sg_working_data_cnt, q->reserved);
 
     printk(
-"  ux_sg_ix %u, orig_sense_len %u\n",
-            q->ux_sg_ix, q->orig_sense_len);
+"  scsiq_rptr %lx, sg_real_addr %lx, sg_list_ptr %lx\n",
+            q->scsiq_rptr, q->sg_real_addr, (ulong) q->sg_list_ptr);
 
     /* Display the request's ADV_SG_BLOCK structures. */
-    for (sg_ptr = q->sg_list_ptr, i = 0; sg_ptr != NULL;
-        sg_ptr = sg_ptr->sg_ptr, i++) {
-        /*
-         * 'sg_ptr' is a physical address. Convert it to a virtual
-         * address by indexing 'i' into the virtual address array
-         * 'sg_list_ptr'.
-         *
-         * At the end of the each iteration of the loop 'sg_ptr' is
-         * converted back into a physical address by setting 'sg_ptr'
-         *  to the next pointer 'sg_ptr->sg_ptr'.
-         */
-        sg_ptr = &(((ADV_SG_BLOCK *) (q->sg_list_ptr))[i]);
-        asc_prt_adv_sgblock(i, sg_ptr);
+    if (q->sg_list_ptr != NULL)
+    {
+        sg_blk_cnt = 0;
+        while (1) {
+            /*
+             * 'sg_ptr' is a physical address. Convert it to a virtual
+             * address by indexing 'sg_blk_cnt' into the virtual address
+             * array 'sg_list_ptr'.
+             *
+             * XXX - Assumes all SG physical blocks are virtually contiguous.
+             */
+            sg_ptr = &(((ADV_SG_BLOCK *) (q->sg_list_ptr))[sg_blk_cnt]);
+            asc_prt_adv_sgblock(sg_blk_cnt, sg_ptr);
+            if (sg_ptr->sg_ptr == NULL)
+            {
+                break;
+            }
+            sg_blk_cnt++;
+        }
     }
 }
 
@@ -10070,26 +10785,20 @@ asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q)
 STATIC void
 asc_prt_adv_sgblock(int sgblockno, ADV_SG_BLOCK *b)
 {
-    int i, s;
-
-    /* Calculate starting entry number for the current block. */
-    s = sgblockno * NO_OF_SG_PER_BLOCK;
+    int i;
 
-    printk(" ADV_SG_BLOCK at addr 0x%lx (sgblockno %lu)\n",
-        (ulong) b, (ulong) sgblockno);
-    printk(
-"  first_entry_no %lu, last_entry_no %lu, sg_ptr 0x%lx\n",
-        (ulong) b->first_entry_no, (ulong) b->last_entry_no, (ulong) b->sg_ptr);
-    ASC_ASSERT(b->first_entry_no - s >= 0);
-    ASC_ASSERT(b->last_entry_no - s >= 0);
-    ASC_ASSERT(b->last_entry_no - s <= NO_OF_SG_PER_BLOCK);
-    ASC_ASSERT(b->first_entry_no - s <= NO_OF_SG_PER_BLOCK);
-    ASC_ASSERT(b->first_entry_no - s <= NO_OF_SG_PER_BLOCK);
-    ASC_ASSERT(b->first_entry_no - s <= b->last_entry_no - s);
-    for (i = b->first_entry_no - s; i <= b->last_entry_no - s; i++) {
-        printk("  [%lu]: sg_addr 0x%lx, sg_count 0x%lx\n",
-            (ulong) i, (ulong) b->sg_list[i].sg_addr,
-            (ulong) b->sg_list[i].sg_count);
+    printk(" ASC_SG_BLOCK at addr %lx (sgblockno %d)\n",
+        (ulong) b, sgblockno);
+    printk("  sg_cnt %u, sg_ptr %lx\n",
+        b->sg_cnt, (ulong) b->sg_ptr);
+    ASC_ASSERT(b->sg_cnt <= NO_OF_SG_PER_BLOCK);
+    if (b->sg_ptr != NULL)
+    {
+        ASC_ASSERT(b->sg_cnt == NO_OF_SG_PER_BLOCK);
+    }
+    for (i = 0; i < b->sg_cnt; i++) {
+        printk("  [%u]: sg_addr %lx, sg_count %lx\n",
+            i, b->sg_list[i].sg_addr, b->sg_list[i].sg_count);
     }
 }
 
@@ -10116,7 +10825,7 @@ asc_prt_hex(char *f, uchar *s, int l)
             k = 8;
             m = 0;
         } else {
-            m = (l - i) % 4 ;
+            m = (l - i) % 4;
         }
 
         for (j = 0; j < k; j++) {
@@ -10176,10 +10885,12 @@ interrupts_enabled(void)
  * --- Asc Library Functions
  */
 
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
 AscGetEisaChipCfg(
                      PortAddr iop_base
 )
+)
 {
     PortAddr            eisa_cfg_iop;
 
@@ -10188,11 +10899,13 @@ AscGetEisaChipCfg(
     return (inpw(eisa_cfg_iop));
 }
 
-STATIC uchar ASC_INIT
+ASC_INITFUNC(
+STATIC uchar,
 AscSetChipScsiID(
                     PortAddr iop_base,
                     uchar new_host_id
 )
+)
 {
     ushort              cfg_lsw;
 
@@ -10206,10 +10919,12 @@ AscSetChipScsiID(
     return (AscGetChipScsiID(iop_base));
 }
 
-STATIC uchar ASC_INIT
+ASC_INITFUNC(
+STATIC uchar,
 AscGetChipScsiCtrl(
                       PortAddr iop_base
 )
+)
 {
     uchar               sc;
 
@@ -10219,11 +10934,13 @@ AscGetChipScsiCtrl(
     return (sc);
 }
 
-STATIC uchar ASC_INIT
+ASC_INITFUNC(
+STATIC uchar,
 AscGetChipVersion(
                      PortAddr iop_base,
                      ushort bus_type
 )
+)
 {
     if ((bus_type & ASC_IS_EISA) != 0) {
         PortAddr            eisa_iop;
@@ -10236,10 +10953,12 @@ AscGetChipVersion(
     return (AscGetChipVerNo(iop_base));
 }
 
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
 AscGetChipBusType(
                      PortAddr iop_base
 )
+)
 {
     ushort              chip_ver;
 
@@ -10269,13 +10988,15 @@ AscGetChipBusType(
     return (0);
 }
 
-STATIC ulong ASC_INIT
+ASC_INITFUNC(
+STATIC ulong,
 AscLoadMicroCode(
                     PortAddr iop_base,
                     ushort s_addr,
                     ushort *mcode_buf,
                     ushort mcode_size
 )
+)
 {
     ulong               chksum;
     ushort              mcode_word_size;
@@ -10293,10 +11014,12 @@ AscLoadMicroCode(
     return (chksum);
 }
 
-STATIC int ASC_INIT
+ASC_INITFUNC(
+STATIC int,
 AscFindSignature(
                     PortAddr iop_base
 )
+)
 {
     ushort              sig_word;
 
@@ -10317,11 +11040,13 @@ STATIC PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] ASC_INITDATA =
     ASC_IOADR_5, ASC_IOADR_6, ASC_IOADR_7, ASC_IOADR_8
 };
 
-STATIC PortAddr ASC_INIT
+ASC_INITFUNC(
+STATIC PortAddr,
 AscSearchIOPortAddr(
                        PortAddr iop_beg,
                        ushort bus_type
 )
+)
 {
     if (bus_type & ASC_IS_VL) {
         while ((iop_beg = AscSearchIOPortAddr11(iop_beg)) != 0) {
@@ -10352,10 +11077,12 @@ AscSearchIOPortAddr(
     return (0);
 }
 
-STATIC PortAddr ASC_INIT
+ASC_INITFUNC(
+STATIC PortAddr,
 AscSearchIOPortAddr11(
                          PortAddr s_addr
 )
+)
 {
     int                 i;
     PortAddr            iop_base;
@@ -10381,30 +11108,36 @@ AscSearchIOPortAddr11(
     return (0);
 }
 
-STATIC void ASC_INIT
+ASC_INITFUNC(
+STATIC void,
 AscToggleIRQAct(
                    PortAddr iop_base
 )
+)
 {
     AscSetChipStatus(iop_base, CIW_IRQ_ACT);
     AscSetChipStatus(iop_base, 0);
     return;
 }
 
-STATIC void ASC_INIT
+ASC_INITFUNC(
+STATIC void,
 AscSetISAPNPWaitForKey(
     void)
+)
 {
     outp(ASC_ISA_PNP_PORT_ADDR, 0x02);
     outp(ASC_ISA_PNP_PORT_WRITE, 0x02);
     return;
 }
 
-STATIC uchar ASC_INIT
+ASC_INITFUNC(
+STATIC uchar,
 AscGetChipIRQ(
                  PortAddr iop_base,
                  ushort bus_type
 )
+)
 {
     ushort              cfg_lsw;
     uchar               chip_irq;
@@ -10434,12 +11167,14 @@ AscGetChipIRQ(
     return ((uchar) (chip_irq + ASC_MIN_IRQ_NO));
 }
 
-STATIC uchar ASC_INIT
+ASC_INITFUNC(
+STATIC uchar,
 AscSetChipIRQ(
                  PortAddr iop_base,
                  uchar irq_no,
                  ushort bus_type
 )
+)
 {
     ushort              cfg_lsw;
 
@@ -10473,10 +11208,12 @@ AscSetChipIRQ(
     return (0);
 }
 
-STATIC void ASC_INIT
+ASC_INITFUNC(
+STATIC void,
 AscEnableIsaDma(
                    uchar dma_channel
 )
+)
 {
     if (dma_channel < 4) {
         outp(0x000B, (ushort) (0xC0 | dma_channel));
@@ -10527,7 +11264,6 @@ AscIsrChipHalted(
     tid_no = ASC_TIX_TO_TID(target_ix);
     target_id = (uchar) ASC_TID_TO_TARGET_ID(tid_no);
     if (asc_dvc->pci_fix_asyn_xfer & target_id) {
-
         asyn_sdtr = ASYN_SDTR_DATA_FIX_PCI_REV_AB;
     } else {
         asyn_sdtr = 0;
@@ -10754,19 +11490,169 @@ AscIsrChipHalted(
                      */
                     boardp->queue_full |= target_id;
                     boardp->queue_full_cnt[tid_no] = cur_dvc_qng;
-#if ASC_QUEUE_FLOW_CONTROL
-                    if (boardp->device[tid_no] != NULL &&
-                        boardp->device[tid_no]->queue_curr_depth >
-                        cur_dvc_qng) {
-                        boardp->device[tid_no]->queue_curr_depth =
-                            cur_dvc_qng;
-                    }
-#endif /* ASC_QUEUE_FLOW_CONTROL */
                 }
             }
         }
         AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
         return (0);
+    } else if (int_halt_code == ASC_HALT_HOST_COPY_SG_LIST_TO_RISC)
+    {
+         uchar              q_no;
+         ushort             q_addr;
+         ulong              srb_ptr;
+         uchar              sg_wk_q_no;
+         uchar              first_sg_wk_q_no;
+         ASC_SCSI_Q         *scsiq; /* Ptr to driver request. */
+         ASC_SG_HEAD        *sg_head; /* Ptr to driver SG request. */
+         ASC_SG_LIST_Q      scsi_sg_q; /* Structure written to queue. */
+         ushort             sg_list_dwords;
+         ushort             sg_entry_cnt;
+         uchar              next_qp;
+         int                i;
+
+         q_no = AscReadLramByte(iop_base, (ushort) ASCV_REQ_SG_LIST_QP);
+         if (q_no == ASC_QLINK_END)
+         {
+             return(0);
+         }
+
+         q_addr = ASC_QNO_TO_QADDR(q_no);
+
+         /* Read request's SRB pointer. */
+         srb_ptr = AscReadLramDWord(iop_base,
+                           (ushort) (q_addr + ASC_SCSIQ_D_SRBPTR));
+
+         /*
+          * Get request's first and working SG queue.
+          */
+         sg_wk_q_no = AscReadLramByte(iop_base,
+             (ushort) (q_addr + ASC_SCSIQ_B_SG_WK_QP));
+
+         first_sg_wk_q_no = AscReadLramByte(iop_base,
+             (ushort) (q_addr + ASC_SCSIQ_B_FIRST_SG_WK_QP));
+
+         /*
+          * Reset request's working SG queue back to the
+          * first SG queue.
+          */
+         AscWriteLramByte(iop_base,
+             (ushort) (q_addr + (ushort) ASC_SCSIQ_B_SG_WK_QP),
+             first_sg_wk_q_no);
+
+         /*
+          * Convert the request's SRB pointer to a host ASC_SCSI_REQ
+          * structure pointer using a macro provided by the driver.
+          * The ASC_SCSI_REQ pointer provides a pointer to the
+          * host ASC_SG_HEAD structure.
+          */
+         scsiq = (ASC_SCSI_Q *) ASC_SRB2SCSIQ(srb_ptr);
+
+         sg_head = scsiq->sg_head;
+
+         /*
+          * Set sg_entry_cnt to the number of SG elements
+          * that will be completed on this interrupt.
+          *
+          * Note: The allocated SG queues contain ASC_MAX_SG_LIST - 1
+          * SG elements. The data_cnt and data_addr fields which
+          * add 1 to the SG element capacity are not used when
+          * restarting SG handling after a halt.
+          */
+         if (scsiq->remain_sg_entry_cnt > (ASC_MAX_SG_LIST - 1))
+         {
+              sg_entry_cnt = ASC_MAX_SG_LIST - 1;
+
+              /*
+               * Keep track of remaining number of SG elements that will
+               * need to be handled on the next interrupt.
+               */
+              scsiq->remain_sg_entry_cnt -= (ASC_MAX_SG_LIST - 1);
+         } else
+         {
+              sg_entry_cnt = scsiq->remain_sg_entry_cnt;
+              scsiq->remain_sg_entry_cnt = 0;
+         }
+
+         /*
+          * Copy SG elements into the list of allocated SG queues.
+          *
+          * Last index completed is saved in scsiq->next_sg_index.
+          */
+         next_qp = first_sg_wk_q_no;
+         q_addr = ASC_QNO_TO_QADDR(next_qp);
+         scsi_sg_q.sg_head_qp = q_no;
+         scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
+         for( i = 0; i < sg_head->queue_cnt; i++)
+         {
+              scsi_sg_q.seq_no = i + 1;
+              if (sg_entry_cnt > ASC_SG_LIST_PER_Q)
+              {
+                  sg_list_dwords = (uchar) (ASC_SG_LIST_PER_Q * 2);
+                  sg_entry_cnt -= ASC_SG_LIST_PER_Q;
+                  /*
+                   * After very first SG queue RISC FW uses next
+                   * SG queue first element then checks sg_list_cnt
+                   * against zero and then decrements, so set
+                   * sg_list_cnt 1 less than number of SG elements
+                   * in each SG queue.
+                   */
+                  scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q - 1;
+                  scsi_sg_q.sg_cur_list_cnt = ASC_SG_LIST_PER_Q - 1;
+              } else {
+                  /*
+                   * This is the last SG queue in the list of
+                   * allocated SG queues. If there are more
+                   * SG elements than will fit in the allocated
+                   * queues, then set the QCSG_SG_XFER_MORE flag.
+                   */
+                  if (scsiq->remain_sg_entry_cnt != 0)
+                  {
+                      scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
+                  } else
+                  {
+                      scsi_sg_q.cntl |= QCSG_SG_XFER_END;
+                  }
+                  /* equals sg_entry_cnt * 2 */
+                  sg_list_dwords = sg_entry_cnt << 1;
+                  scsi_sg_q.sg_list_cnt = sg_entry_cnt - 1;
+                  scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt - 1;
+                  sg_entry_cnt = 0;
+              }
+
+              scsi_sg_q.q_no = next_qp;
+              AscMemWordCopyToLram(iop_base,
+                           (ushort) (q_addr+ASC_SCSIQ_SGHD_CPY_BEG),
+                           (ushort *) &scsi_sg_q,
+                           (ushort) (sizeof(ASC_SG_LIST_Q) >> 1));
+
+              AscMemDWordCopyToLram( iop_base,
+                           (ushort) (q_addr+ASC_SGQ_LIST_BEG ),
+                           (ulong *) &sg_head->sg_list[scsiq->next_sg_index],
+                           (ushort) sg_list_dwords);
+
+              scsiq->next_sg_index += ASC_SG_LIST_PER_Q;
+
+              /*
+               * If the just completed SG queue contained the
+               * last SG element, then no more SG queues need
+               * to be written.
+               */
+              if (scsi_sg_q.cntl & QCSG_SG_XFER_END)
+              {
+                  break;
+              }
+
+              next_qp = AscReadLramByte( iop_base,
+                           ( ushort )( q_addr+ASC_SCSIQ_B_FWD ) );
+              q_addr = ASC_QNO_TO_QADDR( next_qp );
+         }
+
+         /*
+          * Clear the halt condition so the RISC will be restarted
+          * after the return.
+          */
+         AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+         return(0);
     }
     return (0);
 }
@@ -10798,8 +11684,18 @@ _AscCopyLramScsiDoneQ(
                         (ushort) (q_addr + (ushort) ASC_SCSIQ_B_SENSE_LEN));
     scsiq->sense_len = (uchar) _val;
     scsiq->extra_bytes = (uchar) (_val >> 8);
-    scsiq->remain_bytes = AscReadLramWord(iop_base,
-                 (ushort) (q_addr + (ushort) ASC_SCSIQ_DW_REMAIN_XFER_CNT));
+
+    /*
+     * Read high word of remain bytes from alternate location.
+     */
+    scsiq->remain_bytes = (((ulong) AscReadLramWord( iop_base,
+                      (ushort) (q_addr+ (ushort) ASC_SCSIQ_W_ALT_DC1))) << 16);
+    /*
+     * Read low word of remain bytes from original location.
+     */
+    scsiq->remain_bytes += AscReadLramWord(iop_base,
+        (ushort) (q_addr+ (ushort) ASC_SCSIQ_DW_REMAIN_XFER_CNT));
+
     scsiq->remain_bytes &= max_dma_count;
     return (sg_queue_cnt);
 }
@@ -10957,6 +11853,12 @@ AscISR(
 
     iop_base = asc_dvc->iop_base;
     int_pending = FALSE;
+
+    if (AscIsIntPending(iop_base) == 0)
+    {
+        return int_pending;
+    }
+
     if (((asc_dvc->init_state & ASC_INIT_STATE_END_LOAD_MC) == 0)
         || (asc_dvc->isr_callback == 0)
 ) {
@@ -10977,10 +11879,15 @@ AscISR(
     chipstat = AscGetChipStatus(iop_base);
     if (chipstat & CSW_SCSI_RESET_LATCH) {
         if (!(asc_dvc->bus_type & (ASC_IS_VL | ASC_IS_EISA))) {
+            int i = 10;
             int_pending = TRUE;
             asc_dvc->sdtr_done = 0;
             saved_ctrl_reg &= (uchar) (~CC_HALT);
-            while (AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE) ;
+            while ((AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE) &&
+                   (i-- > 0))
+            {
+                  DvcSleepMilliSecond(100);
+            }
             AscSetChipControl(iop_base, (CC_CHIP_RESET | CC_HALT));
             AscSetChipControl(iop_base, CC_HALT);
             AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
@@ -11034,82 +11941,82 @@ STATIC uchar _asc_mcode_buf[] ASC_INITDATA =
   0x0F,  0x0F,  0x0F,  0x0F,  0x0F,  0x0F,  0x0F,  0x0F,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
   0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
   0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0x91,  0x10,  0x0A,  0x05,  0x01,  0x00,  0x00,  0x00,  0x00,  0xFF,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x00,  0xC3,  0x12,  0x0D,  0x05,  0x01,  0x00,  0x00,  0x00,  0x00,  0xFF,  0x00,  0x00,
   0x00,  0x00,  0x00,  0x00,  0xFF,  0x80,  0xFF,  0xFF,  0x01,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x23,  0x00,  0x24,  0x00,  0x00,  0x00,  0x07,  0x00,  0xFF,  0x00,  0x00,  0x00,  0x00,
-  0xFF,  0xFF,  0xFF,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0xE2,  0x88,  0x00,  0x00,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x23,  0x00,  0x00,  0x00,  0x00,  0x00,  0x07,  0x00,  0xFF,  0x00,  0x00,  0x00,  0x00,
+  0xFF,  0xFF,  0xFF,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0xE4,  0x88,  0x00,  0x00,  0x00,  0x00,
   0x80,  0x73,  0x48,  0x04,  0x36,  0x00,  0x00,  0xA2,  0xC2,  0x00,  0x80,  0x73,  0x03,  0x23,  0x36,  0x40,
   0xB6,  0x00,  0x36,  0x00,  0x05,  0xD6,  0x0C,  0xD2,  0x12,  0xDA,  0x00,  0xA2,  0xC2,  0x00,  0x92,  0x80,
   0x1E,  0x98,  0x50,  0x00,  0xF5,  0x00,  0x48,  0x98,  0xDF,  0x23,  0x36,  0x60,  0xB6,  0x00,  0x92,  0x80,
   0x4F,  0x00,  0xF5,  0x00,  0x48,  0x98,  0xEF,  0x23,  0x36,  0x60,  0xB6,  0x00,  0x92,  0x80,  0x80,  0x62,
-  0x92,  0x80,  0x00,  0x46,  0x17,  0xEE,  0x13,  0xEA,  0x02,  0x01,  0x09,  0xD8,  0xCD,  0x04,  0x4D,  0x00,
+  0x92,  0x80,  0x00,  0x46,  0x15,  0xEE,  0x13,  0xEA,  0x02,  0x01,  0x09,  0xD8,  0xCD,  0x04,  0x4D,  0x00,
   0x00,  0xA3,  0xD6,  0x00,  0xA6,  0x97,  0x7F,  0x23,  0x04,  0x61,  0x84,  0x01,  0xE6,  0x84,  0xD2,  0xC1,
-  0x80,  0x73,  0xCD,  0x04,  0x4D,  0x00,  0x00,  0xA3,  0xE2,  0x01,  0xA6,  0x97,  0xCE,  0x81,  0x00,  0x33,
-  0x02,  0x00,  0xC0,  0x88,  0x80,  0x73,  0x80,  0x77,  0x00,  0x01,  0x01,  0xA1,  0x02,  0x01,  0x4F,  0x00,
-  0x84,  0x97,  0x07,  0xA6,  0x0C,  0x01,  0x00,  0x33,  0x03,  0x00,  0xC0,  0x88,  0x03,  0x03,  0x03,  0xDE,
-  0x00,  0x33,  0x05,  0x00,  0xC0,  0x88,  0xCE,  0x00,  0x69,  0x60,  0xCE,  0x00,  0x02,  0x03,  0x4A,  0x60,
-  0x00,  0xA2,  0x80,  0x01,  0x80,  0x63,  0x07,  0xA6,  0x2C,  0x01,  0x80,  0x81,  0x03,  0x03,  0x80,  0x63,
-  0xE2,  0x00,  0x07,  0xA6,  0x3C,  0x01,  0x00,  0x33,  0x04,  0x00,  0xC0,  0x88,  0x03,  0x07,  0x02,  0x01,
-  0x04,  0xCA,  0x0D,  0x23,  0x68,  0x98,  0x4D,  0x04,  0x04,  0x85,  0x05,  0xD8,  0x0D,  0x23,  0x68,  0x98,
-  0xCD,  0x04,  0x15,  0x23,  0xF6,  0x88,  0xFB,  0x23,  0x02,  0x61,  0x82,  0x01,  0x80,  0x63,  0x02,  0x03,
-  0x06,  0xA3,  0x6A,  0x01,  0x00,  0x33,  0x0A,  0x00,  0xC0,  0x88,  0x4E,  0x00,  0x07,  0xA3,  0x76,  0x01,
-  0x00,  0x33,  0x0B,  0x00,  0xC0,  0x88,  0xCD,  0x04,  0x36,  0x2D,  0x00,  0x33,  0x1A,  0x00,  0xC0,  0x88,
-  0x50,  0x04,  0x90,  0x81,  0x06,  0xAB,  0x8A,  0x01,  0x90,  0x81,  0x4E,  0x00,  0x07,  0xA3,  0x9A,  0x01,
-  0x50,  0x00,  0x00,  0xA3,  0x44,  0x01,  0x00,  0x05,  0x84,  0x81,  0x46,  0x97,  0x02,  0x01,  0x05,  0xC6,
-  0x04,  0x23,  0xA0,  0x01,  0x15,  0x23,  0xA1,  0x01,  0xC6,  0x81,  0xFD,  0x23,  0x02,  0x61,  0x82,  0x01,
-  0x0A,  0xDA,  0x4A,  0x00,  0x06,  0x61,  0x00,  0xA0,  0xBC,  0x01,  0x80,  0x63,  0xCD,  0x04,  0x36,  0x2D,
-  0x00,  0x33,  0x1B,  0x00,  0xC0,  0x88,  0x06,  0x23,  0x68,  0x98,  0xCD,  0x04,  0xE6,  0x84,  0x06,  0x01,
-  0x00,  0xA2,  0xDC,  0x01,  0x57,  0x60,  0x00,  0xA0,  0xE2,  0x01,  0xE6,  0x84,  0x80,  0x23,  0xA0,  0x01,
-  0xE6,  0x84,  0x80,  0x73,  0x4B,  0x00,  0x06,  0x61,  0x00,  0xA2,  0x08,  0x02,  0x04,  0x01,  0x0C,  0xDE,
-  0x02,  0x01,  0x03,  0xCC,  0x4F,  0x00,  0x84,  0x97,  0x04,  0x82,  0x08,  0x23,  0x02,  0x41,  0x82,  0x01,
-  0x4F,  0x00,  0x62,  0x97,  0x48,  0x04,  0x84,  0x80,  0xF0,  0x97,  0x00,  0x46,  0x56,  0x00,  0x03,  0xC0,
-  0x01,  0x23,  0xE8,  0x00,  0x81,  0x73,  0x06,  0x29,  0x03,  0x42,  0x06,  0xE2,  0x03,  0xEE,  0x67,  0xEB,
-  0x11,  0x23,  0xF6,  0x88,  0x04,  0x98,  0xF4,  0x80,  0x80,  0x73,  0x80,  0x77,  0x07,  0xA4,  0x32,  0x02,
-  0x7C,  0x95,  0x06,  0xA6,  0x3C,  0x02,  0x03,  0xA6,  0x4C,  0x04,  0xC0,  0x88,  0x04,  0x01,  0x03,  0xD8,
-  0xB2,  0x98,  0x6A,  0x96,  0x4E,  0x82,  0xFE,  0x95,  0x80,  0x67,  0x83,  0x03,  0x80,  0x63,  0xB6,  0x2D,
-  0x02,  0xA6,  0x78,  0x02,  0x07,  0xA6,  0x66,  0x02,  0x06,  0xA6,  0x6A,  0x02,  0x03,  0xA6,  0x6E,  0x02,
-  0x00,  0x33,  0x10,  0x00,  0xC0,  0x88,  0x7C,  0x95,  0x50,  0x82,  0x60,  0x96,  0x50,  0x82,  0x04,  0x23,
-  0xA0,  0x01,  0x14,  0x23,  0xA1,  0x01,  0x3C,  0x84,  0x04,  0x01,  0x0C,  0xDC,  0xE0,  0x23,  0x25,  0x61,
-  0xEF,  0x00,  0x14,  0x01,  0x4F,  0x04,  0xA8,  0x01,  0x6F,  0x00,  0xA5,  0x01,  0x03,  0x23,  0xA4,  0x01,
-  0x06,  0x23,  0x9C,  0x01,  0x24,  0x2B,  0x1C,  0x01,  0x02,  0xA6,  0xB6,  0x02,  0x07,  0xA6,  0x66,  0x02,
-  0x06,  0xA6,  0x6A,  0x02,  0x03,  0xA6,  0x20,  0x04,  0x01,  0xA6,  0xC0,  0x02,  0x00,  0xA6,  0xC0,  0x02,
-  0x00,  0x33,  0x12,  0x00,  0xC0,  0x88,  0x00,  0x0E,  0x80,  0x63,  0x00,  0x43,  0x00,  0xA0,  0x98,  0x02,
-  0x4D,  0x04,  0x04,  0x01,  0x0B,  0xDC,  0xE7,  0x23,  0x04,  0x61,  0x84,  0x01,  0x10,  0x31,  0x12,  0x35,
-  0x14,  0x01,  0xEC,  0x00,  0x6C,  0x38,  0x00,  0x3F,  0x00,  0x00,  0xF6,  0x82,  0x18,  0x23,  0x04,  0x61,
-  0x18,  0xA0,  0xEE,  0x02,  0x04,  0x01,  0x9C,  0xC8,  0x00,  0x33,  0x1F,  0x00,  0xC0,  0x88,  0x08,  0x31,
-  0x0A,  0x35,  0x0C,  0x39,  0x0E,  0x3D,  0x7E,  0x98,  0xB6,  0x2D,  0x01,  0xA6,  0x20,  0x03,  0x00,  0xA6,
-  0x20,  0x03,  0x07,  0xA6,  0x18,  0x03,  0x06,  0xA6,  0x1C,  0x03,  0x03,  0xA6,  0x20,  0x04,  0x02,  0xA6,
-  0x78,  0x02,  0x00,  0x33,  0x33,  0x00,  0xC0,  0x88,  0x7C,  0x95,  0xFA,  0x82,  0x60,  0x96,  0xFA,  0x82,
-  0x82,  0x98,  0x80,  0x42,  0x7E,  0x98,  0x60,  0xE4,  0x04,  0x01,  0x29,  0xC8,  0x31,  0x05,  0x07,  0x01,
-  0x00,  0xA2,  0x60,  0x03,  0x00,  0x43,  0x87,  0x01,  0x05,  0x05,  0x86,  0x98,  0x7E,  0x98,  0x00,  0xA6,
-  0x22,  0x03,  0x07,  0xA6,  0x58,  0x03,  0x03,  0xA6,  0x3C,  0x04,  0x06,  0xA6,  0x5C,  0x03,  0x01,  0xA6,
-  0x22,  0x03,  0x00,  0x33,  0x25,  0x00,  0xC0,  0x88,  0x7C,  0x95,  0x3E,  0x83,  0x60,  0x96,  0x3E,  0x83,
-  0x04,  0x01,  0x0C,  0xCE,  0x03,  0xC8,  0x00,  0x33,  0x42,  0x00,  0xC0,  0x88,  0x00,  0x01,  0x05,  0x05,
-  0xFF,  0xA2,  0x7E,  0x03,  0xB1,  0x01,  0x08,  0x23,  0xB2,  0x01,  0x3A,  0x83,  0x05,  0x05,  0x15,  0x01,
-  0x00,  0xA2,  0x9E,  0x03,  0xEC,  0x00,  0x6E,  0x00,  0x95,  0x01,  0x6C,  0x38,  0x00,  0x3F,  0x00,  0x00,
-  0x01,  0xA6,  0x9A,  0x03,  0x00,  0xA6,  0x9A,  0x03,  0x12,  0x84,  0x80,  0x42,  0x7E,  0x98,  0x01,  0xA6,
-  0xA8,  0x03,  0x00,  0xA6,  0xC0,  0x03,  0x12,  0x84,  0xA6,  0x98,  0x80,  0x42,  0x01,  0xA6,  0xA8,  0x03,
-  0x07,  0xA6,  0xB6,  0x03,  0xD8,  0x83,  0x7C,  0x95,  0xAC,  0x83,  0x00,  0x33,  0x2F,  0x00,  0xC0,  0x88,
-  0xA6,  0x98,  0x80,  0x42,  0x00,  0xA6,  0xC0,  0x03,  0x07,  0xA6,  0xCE,  0x03,  0xD8,  0x83,  0x7C,  0x95,
-  0xC4,  0x83,  0x00,  0x33,  0x26,  0x00,  0xC0,  0x88,  0x38,  0x2B,  0x80,  0x32,  0x80,  0x36,  0x04,  0x23,
-  0xA0,  0x01,  0x12,  0x23,  0xA1,  0x01,  0x12,  0x84,  0x06,  0xF0,  0x06,  0xA4,  0xF6,  0x03,  0x80,  0x6B,
-  0x05,  0x23,  0x83,  0x03,  0x80,  0x63,  0x03,  0xA6,  0x10,  0x04,  0x07,  0xA6,  0x08,  0x04,  0x06,  0xA6,
-  0x0C,  0x04,  0x00,  0x33,  0x17,  0x00,  0xC0,  0x88,  0x7C,  0x95,  0xF6,  0x83,  0x60,  0x96,  0xF6,  0x83,
-  0x20,  0x84,  0x06,  0xF0,  0x06,  0xA4,  0x20,  0x04,  0x80,  0x6B,  0x05,  0x23,  0x83,  0x03,  0x80,  0x63,
+  0x80,  0x73,  0xCD,  0x04,  0x4D,  0x00,  0x00,  0xA3,  0xDA,  0x01,  0xA6,  0x97,  0xC6,  0x81,  0xC2,  0x88,
+  0x80,  0x73,  0x80,  0x77,  0x00,  0x01,  0x01,  0xA1,  0xFE,  0x00,  0x4F,  0x00,  0x84,  0x97,  0x07,  0xA6,
+  0x08,  0x01,  0x00,  0x33,  0x03,  0x00,  0xC2,  0x88,  0x03,  0x03,  0x01,  0xDE,  0xC2,  0x88,  0xCE,  0x00,
+  0x69,  0x60,  0xCE,  0x00,  0x02,  0x03,  0x4A,  0x60,  0x00,  0xA2,  0x78,  0x01,  0x80,  0x63,  0x07,  0xA6,
+  0x24,  0x01,  0x78,  0x81,  0x03,  0x03,  0x80,  0x63,  0xE2,  0x00,  0x07,  0xA6,  0x34,  0x01,  0x00,  0x33,
+  0x04,  0x00,  0xC2,  0x88,  0x03,  0x07,  0x02,  0x01,  0x04,  0xCA,  0x0D,  0x23,  0x68,  0x98,  0x4D,  0x04,
+  0x04,  0x85,  0x05,  0xD8,  0x0D,  0x23,  0x68,  0x98,  0xCD,  0x04,  0x15,  0x23,  0xF8,  0x88,  0xFB,  0x23,
+  0x02,  0x61,  0x82,  0x01,  0x80,  0x63,  0x02,  0x03,  0x06,  0xA3,  0x62,  0x01,  0x00,  0x33,  0x0A,  0x00,
+  0xC2,  0x88,  0x4E,  0x00,  0x07,  0xA3,  0x6E,  0x01,  0x00,  0x33,  0x0B,  0x00,  0xC2,  0x88,  0xCD,  0x04,
+  0x36,  0x2D,  0x00,  0x33,  0x1A,  0x00,  0xC2,  0x88,  0x50,  0x04,  0x88,  0x81,  0x06,  0xAB,  0x82,  0x01,
+  0x88,  0x81,  0x4E,  0x00,  0x07,  0xA3,  0x92,  0x01,  0x50,  0x00,  0x00,  0xA3,  0x3C,  0x01,  0x00,  0x05,
+  0x7C,  0x81,  0x46,  0x97,  0x02,  0x01,  0x05,  0xC6,  0x04,  0x23,  0xA0,  0x01,  0x15,  0x23,  0xA1,  0x01,
+  0xBE,  0x81,  0xFD,  0x23,  0x02,  0x61,  0x82,  0x01,  0x0A,  0xDA,  0x4A,  0x00,  0x06,  0x61,  0x00,  0xA0,
+  0xB4,  0x01,  0x80,  0x63,  0xCD,  0x04,  0x36,  0x2D,  0x00,  0x33,  0x1B,  0x00,  0xC2,  0x88,  0x06,  0x23,
+  0x68,  0x98,  0xCD,  0x04,  0xE6,  0x84,  0x06,  0x01,  0x00,  0xA2,  0xD4,  0x01,  0x57,  0x60,  0x00,  0xA0,
+  0xDA,  0x01,  0xE6,  0x84,  0x80,  0x23,  0xA0,  0x01,  0xE6,  0x84,  0x80,  0x73,  0x4B,  0x00,  0x06,  0x61,
+  0x00,  0xA2,  0x00,  0x02,  0x04,  0x01,  0x0C,  0xDE,  0x02,  0x01,  0x03,  0xCC,  0x4F,  0x00,  0x84,  0x97,
+  0xFC,  0x81,  0x08,  0x23,  0x02,  0x41,  0x82,  0x01,  0x4F,  0x00,  0x62,  0x97,  0x48,  0x04,  0x84,  0x80,
+  0xF0,  0x97,  0x00,  0x46,  0x56,  0x00,  0x03,  0xC0,  0x01,  0x23,  0xE8,  0x00,  0x81,  0x73,  0x06,  0x29,
+  0x03,  0x42,  0x06,  0xE2,  0x03,  0xEE,  0x6B,  0xEB,  0x11,  0x23,  0xF8,  0x88,  0x04,  0x98,  0xF0,  0x80,
+  0x80,  0x73,  0x80,  0x77,  0x07,  0xA4,  0x2A,  0x02,  0x7C,  0x95,  0x06,  0xA6,  0x34,  0x02,  0x03,  0xA6,
+  0x4C,  0x04,  0x46,  0x82,  0x04,  0x01,  0x03,  0xD8,  0xB4,  0x98,  0x6A,  0x96,  0x46,  0x82,  0xFE,  0x95,
+  0x80,  0x67,  0x83,  0x03,  0x80,  0x63,  0xB6,  0x2D,  0x02,  0xA6,  0x6C,  0x02,  0x07,  0xA6,  0x5A,  0x02,
+  0x06,  0xA6,  0x5E,  0x02,  0x03,  0xA6,  0x62,  0x02,  0xC2,  0x88,  0x7C,  0x95,  0x48,  0x82,  0x60,  0x96,
+  0x48,  0x82,  0x04,  0x23,  0xA0,  0x01,  0x14,  0x23,  0xA1,  0x01,  0x3C,  0x84,  0x04,  0x01,  0x0C,  0xDC,
+  0xE0,  0x23,  0x25,  0x61,  0xEF,  0x00,  0x14,  0x01,  0x4F,  0x04,  0xA8,  0x01,  0x6F,  0x00,  0xA5,  0x01,
+  0x03,  0x23,  0xA4,  0x01,  0x06,  0x23,  0x9C,  0x01,  0x24,  0x2B,  0x1C,  0x01,  0x02,  0xA6,  0xAA,  0x02,
+  0x07,  0xA6,  0x5A,  0x02,  0x06,  0xA6,  0x5E,  0x02,  0x03,  0xA6,  0x20,  0x04,  0x01,  0xA6,  0xB4,  0x02,
+  0x00,  0xA6,  0xB4,  0x02,  0x00,  0x33,  0x12,  0x00,  0xC2,  0x88,  0x00,  0x0E,  0x80,  0x63,  0x00,  0x43,
+  0x00,  0xA0,  0x8C,  0x02,  0x4D,  0x04,  0x04,  0x01,  0x0B,  0xDC,  0xE7,  0x23,  0x04,  0x61,  0x84,  0x01,
+  0x10,  0x31,  0x12,  0x35,  0x14,  0x01,  0xEC,  0x00,  0x6C,  0x38,  0x00,  0x3F,  0x00,  0x00,  0xEA,  0x82,
+  0x18,  0x23,  0x04,  0x61,  0x18,  0xA0,  0xE2,  0x02,  0x04,  0x01,  0xA2,  0xC8,  0x00,  0x33,  0x1F,  0x00,
+  0xC2,  0x88,  0x08,  0x31,  0x0A,  0x35,  0x0C,  0x39,  0x0E,  0x3D,  0x7E,  0x98,  0xB6,  0x2D,  0x01,  0xA6,
+  0x14,  0x03,  0x00,  0xA6,  0x14,  0x03,  0x07,  0xA6,  0x0C,  0x03,  0x06,  0xA6,  0x10,  0x03,  0x03,  0xA6,
+  0x20,  0x04,  0x02,  0xA6,  0x6C,  0x02,  0x00,  0x33,  0x33,  0x00,  0xC2,  0x88,  0x7C,  0x95,  0xEE,  0x82,
+  0x60,  0x96,  0xEE,  0x82,  0x82,  0x98,  0x80,  0x42,  0x7E,  0x98,  0x64,  0xE4,  0x04,  0x01,  0x2D,  0xC8,
+  0x31,  0x05,  0x07,  0x01,  0x00,  0xA2,  0x54,  0x03,  0x00,  0x43,  0x87,  0x01,  0x05,  0x05,  0x86,  0x98,
+  0x7E,  0x98,  0x00,  0xA6,  0x16,  0x03,  0x07,  0xA6,  0x4C,  0x03,  0x03,  0xA6,  0x3C,  0x04,  0x06,  0xA6,
+  0x50,  0x03,  0x01,  0xA6,  0x16,  0x03,  0x00,  0x33,  0x25,  0x00,  0xC2,  0x88,  0x7C,  0x95,  0x32,  0x83,
+  0x60,  0x96,  0x32,  0x83,  0x04,  0x01,  0x10,  0xCE,  0x07,  0xC8,  0x05,  0x05,  0xEB,  0x04,  0x00,  0x33,
+  0x00,  0x20,  0xC0,  0x20,  0x81,  0x62,  0x72,  0x83,  0x00,  0x01,  0x05,  0x05,  0xFF,  0xA2,  0x7A,  0x03,
+  0xB1,  0x01,  0x08,  0x23,  0xB2,  0x01,  0x2E,  0x83,  0x05,  0x05,  0x15,  0x01,  0x00,  0xA2,  0x9A,  0x03,
+  0xEC,  0x00,  0x6E,  0x00,  0x95,  0x01,  0x6C,  0x38,  0x00,  0x3F,  0x00,  0x00,  0x01,  0xA6,  0x96,  0x03,
+  0x00,  0xA6,  0x96,  0x03,  0x10,  0x84,  0x80,  0x42,  0x7E,  0x98,  0x01,  0xA6,  0xA4,  0x03,  0x00,  0xA6,
+  0xBC,  0x03,  0x10,  0x84,  0xA8,  0x98,  0x80,  0x42,  0x01,  0xA6,  0xA4,  0x03,  0x07,  0xA6,  0xB2,  0x03,
+  0xD4,  0x83,  0x7C,  0x95,  0xA8,  0x83,  0x00,  0x33,  0x2F,  0x00,  0xC2,  0x88,  0xA8,  0x98,  0x80,  0x42,
+  0x00,  0xA6,  0xBC,  0x03,  0x07,  0xA6,  0xCA,  0x03,  0xD4,  0x83,  0x7C,  0x95,  0xC0,  0x83,  0x00,  0x33,
+  0x26,  0x00,  0xC2,  0x88,  0x38,  0x2B,  0x80,  0x32,  0x80,  0x36,  0x04,  0x23,  0xA0,  0x01,  0x12,  0x23,
+  0xA1,  0x01,  0x10,  0x84,  0x07,  0xF0,  0x06,  0xA4,  0xF4,  0x03,  0x80,  0x6B,  0x80,  0x67,  0x05,  0x23,
+  0x83,  0x03,  0x80,  0x63,  0x03,  0xA6,  0x0E,  0x04,  0x07,  0xA6,  0x06,  0x04,  0x06,  0xA6,  0x0A,  0x04,
+  0x00,  0x33,  0x17,  0x00,  0xC2,  0x88,  0x7C,  0x95,  0xF4,  0x83,  0x60,  0x96,  0xF4,  0x83,  0x20,  0x84,
+  0x07,  0xF0,  0x06,  0xA4,  0x20,  0x04,  0x80,  0x6B,  0x80,  0x67,  0x05,  0x23,  0x83,  0x03,  0x80,  0x63,
   0xB6,  0x2D,  0x03,  0xA6,  0x3C,  0x04,  0x07,  0xA6,  0x34,  0x04,  0x06,  0xA6,  0x38,  0x04,  0x00,  0x33,
-  0x30,  0x00,  0xC0,  0x88,  0x7C,  0x95,  0x20,  0x84,  0x60,  0x96,  0x20,  0x84,  0x1D,  0x01,  0x06,  0xCC,
+  0x30,  0x00,  0xC2,  0x88,  0x7C,  0x95,  0x20,  0x84,  0x60,  0x96,  0x20,  0x84,  0x1D,  0x01,  0x06,  0xCC,
   0x00,  0x33,  0x00,  0x84,  0xC0,  0x20,  0x00,  0x23,  0xEA,  0x00,  0x81,  0x62,  0xA2,  0x0D,  0x80,  0x63,
-  0x07,  0xA6,  0x5A,  0x04,  0x00,  0x33,  0x18,  0x00,  0xC0,  0x88,  0x03,  0x03,  0x80,  0x63,  0xA3,  0x01,
+  0x07,  0xA6,  0x5A,  0x04,  0x00,  0x33,  0x18,  0x00,  0xC2,  0x88,  0x03,  0x03,  0x80,  0x63,  0xA3,  0x01,
   0x07,  0xA4,  0x64,  0x04,  0x23,  0x01,  0x00,  0xA2,  0x86,  0x04,  0x0A,  0xA0,  0x76,  0x04,  0xE0,  0x00,
-  0x00,  0x33,  0x1D,  0x00,  0xC0,  0x88,  0x0B,  0xA0,  0x82,  0x04,  0xE0,  0x00,  0x00,  0x33,  0x1E,  0x00,
-  0xC0,  0x88,  0x42,  0x23,  0xF6,  0x88,  0x00,  0x23,  0x22,  0xA3,  0xE6,  0x04,  0x08,  0x23,  0x22,  0xA3,
+  0x00,  0x33,  0x1D,  0x00,  0xC2,  0x88,  0x0B,  0xA0,  0x82,  0x04,  0xE0,  0x00,  0x00,  0x33,  0x1E,  0x00,
+  0xC2,  0x88,  0x42,  0x23,  0xF8,  0x88,  0x00,  0x23,  0x22,  0xA3,  0xE6,  0x04,  0x08,  0x23,  0x22,  0xA3,
   0xA2,  0x04,  0x28,  0x23,  0x22,  0xA3,  0xAE,  0x04,  0x02,  0x23,  0x22,  0xA3,  0xC4,  0x04,  0x42,  0x23,
-  0xF6,  0x88,  0x4A,  0x00,  0x06,  0x61,  0x00,  0xA0,  0xAE,  0x04,  0x45,  0x23,  0xF6,  0x88,  0x04,  0x98,
-  0x00,  0xA2,  0xC0,  0x04,  0xB2,  0x98,  0x00,  0x33,  0x00,  0x82,  0xC0,  0x20,  0x81,  0x62,  0xF0,  0x81,
-  0x47,  0x23,  0xF6,  0x88,  0x04,  0x01,  0x0B,  0xDE,  0x04,  0x98,  0xB2,  0x98,  0x00,  0x33,  0x00,  0x81,
-  0xC0,  0x20,  0x81,  0x62,  0x14,  0x01,  0x00,  0xA0,  0x08,  0x02,  0x43,  0x23,  0xF6,  0x88,  0x04,  0x23,
+  0xF8,  0x88,  0x4A,  0x00,  0x06,  0x61,  0x00,  0xA0,  0xAE,  0x04,  0x45,  0x23,  0xF8,  0x88,  0x04,  0x98,
+  0x00,  0xA2,  0xC0,  0x04,  0xB4,  0x98,  0x00,  0x33,  0x00,  0x82,  0xC0,  0x20,  0x81,  0x62,  0xE8,  0x81,
+  0x47,  0x23,  0xF8,  0x88,  0x04,  0x01,  0x0B,  0xDE,  0x04,  0x98,  0xB4,  0x98,  0x00,  0x33,  0x00,  0x81,
+  0xC0,  0x20,  0x81,  0x62,  0x14,  0x01,  0x00,  0xA0,  0x00,  0x02,  0x43,  0x23,  0xF8,  0x88,  0x04,  0x23,
   0xA0,  0x01,  0x44,  0x23,  0xA1,  0x01,  0x80,  0x73,  0x4D,  0x00,  0x03,  0xA3,  0xF4,  0x04,  0x00,  0x33,
-  0x27,  0x00,  0xC0,  0x88,  0x04,  0x01,  0x04,  0xDC,  0x02,  0x23,  0xA2,  0x01,  0x04,  0x23,  0xA0,  0x01,
+  0x27,  0x00,  0xC2,  0x88,  0x04,  0x01,  0x04,  0xDC,  0x02,  0x23,  0xA2,  0x01,  0x04,  0x23,  0xA0,  0x01,
   0x04,  0x98,  0x26,  0x95,  0x4B,  0x00,  0xF6,  0x00,  0x4F,  0x04,  0x4F,  0x00,  0x00,  0xA3,  0x22,  0x05,
   0x00,  0x05,  0x76,  0x00,  0x06,  0x61,  0x00,  0xA2,  0x1C,  0x05,  0x0A,  0x85,  0x46,  0x97,  0xCD,  0x04,
   0x24,  0x85,  0x48,  0x04,  0x84,  0x80,  0x02,  0x01,  0x03,  0xDA,  0x80,  0x23,  0x82,  0x01,  0x34,  0x85,
@@ -11118,16 +12025,16 @@ STATIC uchar _asc_mcode_buf[] ASC_INITDATA =
   0x04,  0x01,  0x02,  0xC8,  0x30,  0x01,  0x80,  0x01,  0xF7,  0x04,  0x03,  0x01,  0x49,  0x04,  0x80,  0x01,
   0xC9,  0x00,  0x00,  0x05,  0x00,  0x01,  0xFF,  0xA0,  0x60,  0x05,  0x77,  0x04,  0x01,  0x23,  0xEA,  0x00,
   0x5D,  0x00,  0xFE,  0xC7,  0x00,  0x62,  0x00,  0x23,  0xEA,  0x00,  0x00,  0x63,  0x07,  0xA4,  0xF8,  0x05,
-  0x03,  0x03,  0x02,  0xA0,  0x8E,  0x05,  0xF4,  0x85,  0x00,  0x33,  0x2D,  0x00,  0xC0,  0x88,  0x04,  0xA0,
+  0x03,  0x03,  0x02,  0xA0,  0x8E,  0x05,  0xF4,  0x85,  0x00,  0x33,  0x2D,  0x00,  0xC2,  0x88,  0x04,  0xA0,
   0xB8,  0x05,  0x80,  0x63,  0x00,  0x23,  0xDF,  0x00,  0x4A,  0x00,  0x06,  0x61,  0x00,  0xA2,  0xA4,  0x05,
   0x1D,  0x01,  0x06,  0xD6,  0x02,  0x23,  0x02,  0x41,  0x82,  0x01,  0x50,  0x00,  0x62,  0x97,  0x04,  0x85,
   0x04,  0x23,  0x02,  0x41,  0x82,  0x01,  0x04,  0x85,  0x08,  0xA0,  0xBE,  0x05,  0xF4,  0x85,  0x03,  0xA0,
   0xC4,  0x05,  0xF4,  0x85,  0x01,  0xA0,  0xCE,  0x05,  0x88,  0x00,  0x80,  0x63,  0xCC,  0x86,  0x07,  0xA0,
   0xEE,  0x05,  0x5F,  0x00,  0x00,  0x2B,  0xDF,  0x08,  0x00,  0xA2,  0xE6,  0x05,  0x80,  0x67,  0x80,  0x63,
-  0x01,  0xA2,  0x7A,  0x06,  0x7C,  0x85,  0x06,  0x23,  0x68,  0x98,  0x48,  0x23,  0xF6,  0x88,  0x07,  0x23,
+  0x01,  0xA2,  0x7A,  0x06,  0x7C,  0x85,  0x06,  0x23,  0x68,  0x98,  0x48,  0x23,  0xF8,  0x88,  0x07,  0x23,
   0x80,  0x00,  0x06,  0x87,  0x80,  0x63,  0x7C,  0x85,  0x00,  0x23,  0xDF,  0x00,  0x00,  0x63,  0x4A,  0x00,
   0x06,  0x61,  0x00,  0xA2,  0x36,  0x06,  0x1D,  0x01,  0x16,  0xD4,  0xC0,  0x23,  0x07,  0x41,  0x83,  0x03,
-  0x80,  0x63,  0x06,  0xA6,  0x1C,  0x06,  0x00,  0x33,  0x37,  0x00,  0xC0,  0x88,  0x1D,  0x01,  0x01,  0xD6,
+  0x80,  0x63,  0x06,  0xA6,  0x1C,  0x06,  0x00,  0x33,  0x37,  0x00,  0xC2,  0x88,  0x1D,  0x01,  0x01,  0xD6,
   0x20,  0x23,  0x63,  0x60,  0x83,  0x03,  0x80,  0x63,  0x02,  0x23,  0xDF,  0x00,  0x07,  0xA6,  0x7C,  0x05,
   0xEF,  0x04,  0x6F,  0x00,  0x00,  0x63,  0x4B,  0x00,  0x06,  0x41,  0xCB,  0x00,  0x52,  0x00,  0x06,  0x61,
   0x00,  0xA2,  0x4E,  0x06,  0x1D,  0x01,  0x03,  0xCA,  0xC0,  0x23,  0x07,  0x41,  0x00,  0x63,  0x1D,  0x01,
@@ -11139,12 +12046,12 @@ STATIC uchar _asc_mcode_buf[] ASC_INITDATA =
   0x01,  0x00,  0x06,  0xA6,  0xAA,  0x06,  0x07,  0xA6,  0x7C,  0x05,  0x40,  0x0E,  0x80,  0x63,  0x00,  0x43,
   0x00,  0xA0,  0xA2,  0x06,  0x06,  0xA6,  0xBC,  0x06,  0x07,  0xA6,  0x7C,  0x05,  0x80,  0x67,  0x40,  0x0E,
   0x80,  0x63,  0x07,  0xA6,  0x7C,  0x05,  0x00,  0x23,  0xDF,  0x00,  0x00,  0x63,  0x07,  0xA6,  0xD6,  0x06,
-  0x00,  0x33,  0x2A,  0x00,  0xC0,  0x88,  0x03,  0x03,  0x80,  0x63,  0x89,  0x00,  0x0A,  0x2B,  0x07,  0xA6,
-  0xE8,  0x06,  0x00,  0x33,  0x29,  0x00,  0xC0,  0x88,  0x00,  0x43,  0x00,  0xA2,  0xF4,  0x06,  0xC0,  0x0E,
+  0x00,  0x33,  0x2A,  0x00,  0xC2,  0x88,  0x03,  0x03,  0x80,  0x63,  0x89,  0x00,  0x0A,  0x2B,  0x07,  0xA6,
+  0xE8,  0x06,  0x00,  0x33,  0x29,  0x00,  0xC2,  0x88,  0x00,  0x43,  0x00,  0xA2,  0xF4,  0x06,  0xC0,  0x0E,
   0x80,  0x63,  0xDE,  0x86,  0xC0,  0x0E,  0x00,  0x33,  0x00,  0x80,  0xC0,  0x20,  0x81,  0x62,  0x04,  0x01,
   0x02,  0xDA,  0x80,  0x63,  0x7C,  0x85,  0x80,  0x7B,  0x80,  0x63,  0x06,  0xA6,  0x8C,  0x06,  0x00,  0x33,
-  0x2C,  0x00,  0xC0,  0x88,  0x0C,  0xA2,  0x2E,  0x07,  0xFE,  0x95,  0x83,  0x03,  0x80,  0x63,  0x06,  0xA6,
-  0x2C,  0x07,  0x07,  0xA6,  0x7C,  0x05,  0x00,  0x33,  0x3D,  0x00,  0xC0,  0x88,  0x00,  0x00,  0x80,  0x67,
+  0x2C,  0x00,  0xC2,  0x88,  0x0C,  0xA2,  0x2E,  0x07,  0xFE,  0x95,  0x83,  0x03,  0x80,  0x63,  0x06,  0xA6,
+  0x2C,  0x07,  0x07,  0xA6,  0x7C,  0x05,  0x00,  0x33,  0x3D,  0x00,  0xC2,  0x88,  0x00,  0x00,  0x80,  0x67,
   0x83,  0x03,  0x80,  0x63,  0x0C,  0xA0,  0x44,  0x07,  0x07,  0xA6,  0x7C,  0x05,  0xBF,  0x23,  0x04,  0x61,
   0x84,  0x01,  0xE6,  0x84,  0x00,  0x63,  0xF0,  0x04,  0x01,  0x01,  0xF1,  0x00,  0x00,  0x01,  0xF2,  0x00,
   0x01,  0x05,  0x80,  0x01,  0x72,  0x04,  0x71,  0x00,  0x81,  0x01,  0x70,  0x04,  0x80,  0x05,  0x81,  0x05,
@@ -11154,7 +12061,7 @@ STATIC uchar _asc_mcode_buf[] ASC_INITDATA =
   0x80,  0x01,  0x70,  0x04,  0x71,  0x00,  0x80,  0x01,  0x72,  0x00,  0x81,  0x01,  0x71,  0x04,  0x70,  0x00,
   0x81,  0x01,  0x70,  0x04,  0x00,  0x63,  0x00,  0x23,  0xB3,  0x01,  0x83,  0x05,  0xA3,  0x01,  0xA2,  0x01,
   0xA1,  0x01,  0x01,  0x23,  0xA0,  0x01,  0x00,  0x01,  0xC8,  0x00,  0x03,  0xA1,  0xC4,  0x07,  0x00,  0x33,
-  0x07,  0x00,  0xC0,  0x88,  0x80,  0x05,  0x81,  0x05,  0x04,  0x01,  0x11,  0xC8,  0x48,  0x00,  0xB0,  0x01,
+  0x07,  0x00,  0xC2,  0x88,  0x80,  0x05,  0x81,  0x05,  0x04,  0x01,  0x11,  0xC8,  0x48,  0x00,  0xB0,  0x01,
   0xB1,  0x01,  0x08,  0x23,  0xB2,  0x01,  0x05,  0x01,  0x48,  0x04,  0x00,  0x43,  0x00,  0xA2,  0xE4,  0x07,
   0x00,  0x05,  0xDA,  0x87,  0x00,  0x01,  0xC8,  0x00,  0xFF,  0x23,  0x80,  0x01,  0x05,  0x05,  0x00,  0x63,
   0xF7,  0x04,  0x1A,  0x09,  0xF6,  0x08,  0x6E,  0x04,  0x00,  0x02,  0x80,  0x43,  0x76,  0x08,  0x80,  0x02,
@@ -11165,19 +12072,19 @@ STATIC uchar _asc_mcode_buf[] ASC_INITDATA =
   0x26,  0x95,  0x24,  0x88,  0x73,  0x04,  0x00,  0x63,  0xF3,  0x04,  0x75,  0x04,  0x5A,  0x88,  0x02,  0x01,
   0x04,  0xD8,  0x46,  0x97,  0x04,  0x98,  0x26,  0x95,  0x4A,  0x88,  0x75,  0x00,  0x00,  0xA3,  0x64,  0x08,
   0x00,  0x05,  0x4E,  0x88,  0x73,  0x04,  0x00,  0x63,  0x80,  0x7B,  0x80,  0x63,  0x06,  0xA6,  0x76,  0x08,
-  0x00,  0x33,  0x3E,  0x00,  0xC0,  0x88,  0x80,  0x67,  0x83,  0x03,  0x80,  0x63,  0x00,  0x63,  0x38,  0x2B,
+  0x00,  0x33,  0x3E,  0x00,  0xC2,  0x88,  0x80,  0x67,  0x83,  0x03,  0x80,  0x63,  0x00,  0x63,  0x38,  0x2B,
   0x9C,  0x88,  0x38,  0x2B,  0x92,  0x88,  0x32,  0x09,  0x31,  0x05,  0x92,  0x98,  0x05,  0x05,  0xB2,  0x09,
   0x00,  0x63,  0x00,  0x32,  0x00,  0x36,  0x00,  0x3A,  0x00,  0x3E,  0x00,  0x63,  0x80,  0x32,  0x80,  0x36,
-  0x80,  0x3A,  0x80,  0x3E,  0x00,  0x63,  0x38,  0x2B,  0x40,  0x32,  0x40,  0x36,  0x40,  0x3A,  0x40,  0x3E,
-  0x00,  0x63,  0x5A,  0x20,  0xC9,  0x40,  0x00,  0xA0,  0xB2,  0x08,  0x5D,  0x00,  0xFE,  0xC3,  0x00,  0x63,
-  0x80,  0x73,  0xE6,  0x20,  0x02,  0x23,  0xE8,  0x00,  0x82,  0x73,  0xFF,  0xFD,  0x80,  0x73,  0x13,  0x23,
-  0xF6,  0x88,  0x66,  0x20,  0xC0,  0x20,  0x04,  0x23,  0xA0,  0x01,  0xA1,  0x23,  0xA1,  0x01,  0x81,  0x62,
-  0xE0,  0x88,  0x80,  0x73,  0x80,  0x77,  0x68,  0x00,  0x00,  0xA2,  0x80,  0x00,  0x03,  0xC2,  0xF1,  0xC7,
-  0x41,  0x23,  0xF6,  0x88,  0x11,  0x23,  0xA1,  0x01,  0x04,  0x23,  0xA0,  0x01,  0xE6,  0x84,
+  0x80,  0x3A,  0x80,  0x3E,  0xB4,  0x3D,  0x00,  0x63,  0x38,  0x2B,  0x40,  0x32,  0x40,  0x36,  0x40,  0x3A,
+  0x40,  0x3E,  0x00,  0x63,  0x5A,  0x20,  0xC9,  0x40,  0x00,  0xA0,  0xB4,  0x08,  0x5D,  0x00,  0xFE,  0xC3,
+  0x00,  0x63,  0x80,  0x73,  0xE6,  0x20,  0x02,  0x23,  0xE8,  0x00,  0x82,  0x73,  0xFF,  0xFD,  0x80,  0x73,
+  0x13,  0x23,  0xF8,  0x88,  0x66,  0x20,  0xC0,  0x20,  0x04,  0x23,  0xA0,  0x01,  0xA1,  0x23,  0xA1,  0x01,
+  0x81,  0x62,  0xE2,  0x88,  0x80,  0x73,  0x80,  0x77,  0x68,  0x00,  0x00,  0xA2,  0x80,  0x00,  0x03,  0xC2,
+  0xF1,  0xC7,  0x41,  0x23,  0xF8,  0x88,  0x11,  0x23,  0xA1,  0x01,  0x04,  0x23,  0xA0,  0x01,  0xE6,  0x84,
 };
 
 STATIC ushort _asc_mcode_size ASC_INITDATA = sizeof(_asc_mcode_buf);
-STATIC ulong _asc_mcode_chksum ASC_INITDATA = 0x012B5442UL;
+STATIC ulong  _asc_mcode_chksum ASC_INITDATA = 0x012C453FUL;
 
 #define ASC_SYN_OFFSET_ONE_DISABLE_LIST  16
 STATIC uchar _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] =
@@ -11244,7 +12151,7 @@ AscExeScsiQueue(
     n_q_required = 1;
     if (scsiq->cdbptr[0] == SCSICMD_RequestSense) {
         if ((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) {
-            asc_dvc->sdtr_done &= ~scsiq->q1.target_id ;
+            asc_dvc->sdtr_done &= ~scsiq->q1.target_id;
             sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
             AscMsgOutSDTR(asc_dvc,
                           asc_dvc->sdtr_period_tbl[(sdtr_data >> 4) &
@@ -11266,12 +12173,15 @@ AscExeScsiQueue(
             DvcLeaveCritical(last_int_level);
             return (ERR);
         }
-        if (sg_entry_cnt > ASC_MAX_SG_LIST) {
-            return (ERR);
+#if !CC_VERY_LONG_SG_LIST
+        if (sg_entry_cnt > ASC_MAX_SG_LIST)
+        {
+            return(ERR);
         }
+#endif /* !CC_VERY_LONG_SG_LIST */
         if (sg_entry_cnt == 1) {
-            scsiq->q1.data_addr = sg_head->sg_list[0].addr;
-            scsiq->q1.data_cnt = sg_head->sg_list[0].bytes;
+            scsiq->q1.data_addr = (ulong) sg_head->sg_list[0].addr;
+            scsiq->q1.data_cnt = (ulong) sg_head->sg_list[0].bytes;
             scsiq->q1.cntl &= ~(QC_SG_HEAD | QC_SG_SWAP_QUEUE);
         }
         sg_entry_cnt_minus_one = sg_entry_cnt - 1;
@@ -11283,7 +12193,7 @@ AscExeScsiQueue(
         if (scsiq->q1.cntl & QC_SG_HEAD) {
             data_cnt = 0;
             for (i = 0; i < sg_entry_cnt; i++) {
-                data_cnt += sg_head->sg_list[i].bytes;
+                data_cnt += (ulong) sg_head->sg_list[i].bytes;
             }
         } else {
             data_cnt = scsiq->q1.data_cnt;
@@ -11317,8 +12227,9 @@ AscExeScsiQueue(
             if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
                 if ((scsi_cmd == SCSICMD_Read6) ||
                     (scsi_cmd == SCSICMD_Read10)) {
-                    addr = sg_head->sg_list[sg_entry_cnt_minus_one].addr +
-                      sg_head->sg_list[sg_entry_cnt_minus_one].bytes;
+                    addr =
+                        (ulong) sg_head->sg_list[sg_entry_cnt_minus_one].addr +
+                        (ulong) sg_head->sg_list[sg_entry_cnt_minus_one].bytes;
                     extra_bytes = (uchar) ((ushort) addr & 0x0003);
                     if ((extra_bytes != 0) &&
                         ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES)
@@ -11332,6 +12243,15 @@ AscExeScsiQueue(
             }
         }
         sg_head->entry_to_copy = sg_head->entry_cnt;
+        /*
+         * Set the sg_entry_cnt to the maximum possible. The rest of
+         * the SG elements will be copied when the RISC completes the
+         * SG elements that fit and halts.
+         */
+        if (sg_entry_cnt > ASC_MAX_SG_LIST)
+        {
+             sg_entry_cnt = ASC_MAX_SG_LIST;
+        }
         n_q_required = AscSgListToQueue(sg_entry_cnt);
         if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, n_q_required) >=
             (uint) n_q_required) || ((scsiq->q1.cntl & QC_URGENT) != 0)) {
@@ -11558,9 +12478,39 @@ AscPutReadySgListQueue(
     sg_head = scsiq->sg_head;
     saved_data_addr = scsiq->q1.data_addr;
     saved_data_cnt = scsiq->q1.data_cnt;
-    scsiq->q1.data_addr = sg_head->sg_list[0].addr;
-    scsiq->q1.data_cnt = sg_head->sg_list[0].bytes;
-    sg_entry_cnt = sg_head->entry_cnt - 1;
+    scsiq->q1.data_addr = (ulong) sg_head->sg_list[0].addr;
+    scsiq->q1.data_cnt = (ulong) sg_head->sg_list[0].bytes;
+    /*
+     * If sg_head->entry_cnt is greater than ASC_MAX_SG_LIST
+     * then not all SG elements will fit in the allocated queues.
+     * The rest of the SG elements will be copied when the RISC
+     * completes the SG elements that fit and halts.
+     */
+    if (sg_head->entry_cnt > ASC_MAX_SG_LIST)
+    {
+         /*
+          * Set sg_entry_cnt to be the number of SG elements that
+          * will fit in the allocated SG queues. It is minus 1 because
+          * first SG element handled above. ASC_MAX_SG_LIST is already
+          * inflated by 1 to account for this. For example it may
+          * be 50 which is 1 + 7 queues * 7 SG elements.
+          */
+         sg_entry_cnt = ASC_MAX_SG_LIST - 1;
+
+         /*
+          * Keep track of remaining number of SG elements that will
+          * need to be handled from a_isr.c.
+          */
+         scsiq->remain_sg_entry_cnt = sg_head->entry_cnt - ASC_MAX_SG_LIST;
+    } else
+    {
+         /*
+          * Set sg_entry_cnt to be the number of SG elements that
+          * will fit in the allocated SG queues. Refer to comment
+          * above regarding why it is - 1.
+          */
+         sg_entry_cnt = sg_head->entry_cnt - 1;
+    }
     if (sg_entry_cnt != 0) {
         scsiq->q1.cntl |= QC_SG_HEAD;
         q_addr = ASC_QNO_TO_QADDR(q_no);
@@ -11581,7 +12531,19 @@ AscPutReadySgListQueue(
                     scsi_sg_q.sg_cur_list_cnt = ASC_SG_LIST_PER_Q - 1;
                 }
             } else {
-                scsi_sg_q.cntl |= QCSG_SG_XFER_END;
+                /*
+                 * This is the last SG queue in the list of
+                 * allocated SG queues. If there are more
+                 * SG elements than will fit in the allocated
+                 * queues, then set the QCSG_SG_XFER_MORE flag.
+                 */
+                if (sg_head->entry_cnt > ASC_MAX_SG_LIST)
+                {
+                    scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
+                } else
+                {
+                    scsi_sg_q.cntl |= QCSG_SG_XFER_END;
+                }
                 sg_list_dwords = sg_entry_cnt << 1;
                 if (i == 0) {
                     scsi_sg_q.sg_list_cnt = sg_entry_cnt;
@@ -11605,6 +12567,7 @@ AscPutReadySgListQueue(
                               (ulong *) & sg_head->sg_list[sg_index],
                                   (ushort) sg_list_dwords);
             sg_index += ASC_SG_LIST_PER_Q;
+            scsiq->next_sg_index = sg_index;
         }
     } else {
         scsiq->q1.cntl &= ~QC_SG_HEAD;
@@ -11790,7 +12753,7 @@ AscSetChipSynRegAtID(
         if (org_id == (0x01 << i))
             break;
     }
-    org_id = i;
+    org_id = (ASC_SCSI_BIT_ID_TYPE) i;
     AscWriteChipDvcID(iop_base, id);
     if (AscReadChipDvcID(iop_base) == (0x01 << id)) {
         AscSetBank(iop_base, 0);
@@ -11929,7 +12892,7 @@ _AscWaitQDone(
     uchar               q_status;
     int                 count = 0;
 
-    while (scsiq->q1.q_no == 0) ;
+    while (scsiq->q1.q_no == 0);
     q_addr = ASC_QNO_TO_QADDR(scsiq->q1.q_no);
     do {
         q_status = AscReadLramByte(iop_base, q_addr + ASC_SCSIQ_B_STATUS);
@@ -12024,7 +12987,7 @@ AscGetSynPeriodIndex(
 
     period_table = asc_dvc->sdtr_period_tbl;
     max_index = (int) asc_dvc->max_sdtr_index;
-    min_index = (int)asc_dvc->host_init_sdtr_index ;
+    min_index = (int)asc_dvc->host_init_sdtr_index;
     if ((syn_time <= period_table[max_index])) {
         for (i = min_index; i < (max_index - 1); i++) {
             if (syn_time <= period_table[i]) {
@@ -12323,7 +13286,7 @@ AscGetOnePhyAddr(
     if (sg_head.entry_cnt > 1) {
         return (0L);
     }
-    return (sg_head.sg_list[0].addr);
+    return ((ulong) sg_head.sg_list[0].addr);
 }
 
 STATIC void
@@ -12338,10 +13301,12 @@ DvcDelayNanoSecond(ASC_DVC_VAR asc_ptr_type * asc_dvc, ulong nano_sec)
     udelay((nano_sec + 999)/1000);
 }
 
-STATIC ulong ASC_INIT
+ASC_INITFUNC(
+STATIC ulong,
 AscGetEisaProductID(
                        PortAddr iop_base
 )
+)
 {
     PortAddr            eisa_iop;
     ushort              product_id_high, product_id_low;
@@ -12354,10 +13319,12 @@ AscGetEisaProductID(
     return (product_id);
 }
 
-STATIC PortAddr ASC_INIT
+ASC_INITFUNC(
+STATIC PortAddr,
 AscSearchIOPortAddrEISA(
                            PortAddr iop_base
 )
+)
 {
     ulong               eisa_product_id;
 
@@ -12530,9 +13497,13 @@ AscResetChipAndScsiBus(
 )
 {
     PortAddr    iop_base;
+    int         i = 10;
 
     iop_base = asc_dvc->iop_base;
-    while (AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE) ;
+    while ((AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE) && (i-- > 0))
+    {
+          DvcSleepMilliSecond(100);
+    }
     AscStopChip(iop_base);
     AscSetChipControl(iop_base, CC_CHIP_RESET | CC_SCSI_RESET | CC_HALT);
     DvcDelayNanoSecond(asc_dvc, 60000);
@@ -12546,10 +13517,12 @@ AscResetChipAndScsiBus(
     return (AscIsChipHalted(iop_base));
 }
 
-STATIC ulong ASC_INIT
+ASC_INITFUNC(
+STATIC ulong,
 AscGetMaxDmaCount(
                      ushort bus_type
 )
+)
 {
     if (bus_type & ASC_IS_ISA)
         return (ASC_MAX_ISA_DMA_COUNT);
@@ -12558,10 +13531,12 @@ AscGetMaxDmaCount(
     return (ASC_MAX_PCI_DMA_COUNT);
 }
 
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
 AscGetIsaDmaChannel(
                        PortAddr iop_base
 )
+)
 {
     ushort              channel;
 
@@ -12573,11 +13548,13 @@ AscGetIsaDmaChannel(
     return (channel + 4);
 }
 
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
 AscSetIsaDmaChannel(
                        PortAddr iop_base,
                        ushort dma_channel
 )
+)
 {
     ushort              cfg_lsw;
     uchar               value;
@@ -12595,11 +13572,13 @@ AscSetIsaDmaChannel(
     return (0);
 }
 
-STATIC uchar ASC_INIT
+ASC_INITFUNC(
+STATIC uchar,
 AscSetIsaDmaSpeed(
                      PortAddr iop_base,
                      uchar speed_value
 )
+)
 {
     speed_value &= 0x07;
     AscSetBank(iop_base, 1);
@@ -12608,10 +13587,12 @@ AscSetIsaDmaSpeed(
     return (AscGetIsaDmaSpeed(iop_base));
 }
 
-STATIC uchar ASC_INIT
+ASC_INITFUNC(
+STATIC uchar,
 AscGetIsaDmaSpeed(
                      PortAddr iop_base
 )
+)
 {
     uchar               speed_value;
 
@@ -12622,10 +13603,12 @@ AscGetIsaDmaSpeed(
     return (speed_value);
 }
 
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
 AscReadPCIConfigWord(
     ASC_DVC_VAR asc_ptr_type *asc_dvc,
     ushort pci_config_offset)
+)
 {
     uchar       lsb, msb;
 
@@ -12634,10 +13617,12 @@ AscReadPCIConfigWord(
     return ((ushort) ((msb << 8) | lsb));
 }
 
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
 AscInitGetConfig(
         ASC_DVC_VAR asc_ptr_type * asc_dvc
 )
+)
 {
     ushort              warn_code;
     PortAddr            iop_base;
@@ -12717,10 +13702,12 @@ AscInitGetConfig(
     return(warn_code);
 }
 
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
 AscInitSetConfig(
                     ASC_DVC_VAR asc_ptr_type * asc_dvc
 )
+)
 {
     ushort              warn_code = 0;
 
@@ -12736,10 +13723,12 @@ AscInitSetConfig(
     return (warn_code);
 }
 
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
 AscInitFromAscDvcVar(
                         ASC_DVC_VAR asc_ptr_type * asc_dvc
 )
+)
 {
     PortAddr            iop_base;
     ushort              cfg_msw;
@@ -12797,16 +13786,15 @@ AscInitFromAscDvcVar(
     return (warn_code);
 }
 
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
 AscInitAsc1000Driver(
                         ASC_DVC_VAR asc_ptr_type * asc_dvc
 )
+)
 {
     ushort              warn_code;
     PortAddr            iop_base;
-    extern ushort       _asc_mcode_size;
-    extern ulong        _asc_mcode_chksum;
-    extern uchar        _asc_mcode_buf[];
 
     iop_base = asc_dvc->iop_base;
     warn_code = 0;
@@ -12837,10 +13825,12 @@ AscInitAsc1000Driver(
     return (warn_code);
 }
 
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
 AscInitAscDvcVar(
                     ASC_DVC_VAR asc_ptr_type * asc_dvc
 )
+)
 {
     int                 i;
     PortAddr            iop_base;
@@ -12869,12 +13859,12 @@ AscInitAscDvcVar(
     asc_dvc->no_scam = 0;
     asc_dvc->unit_not_ready = 0;
     asc_dvc->queue_full_or_busy = 0;
-    asc_dvc->redo_scam = 0 ;
-    asc_dvc->res2 = 0 ;
-    asc_dvc->host_init_sdtr_index = 0 ;
-    asc_dvc->res7 = 0 ;
-    asc_dvc->res8 = 0 ;
-    asc_dvc->cfg->can_tagged_qng = 0 ;
+    asc_dvc->redo_scam = 0;
+    asc_dvc->res2 = 0;
+    asc_dvc->host_init_sdtr_index = 0;
+    asc_dvc->res7 = 0;
+    asc_dvc->res8 = 0;
+    asc_dvc->cfg->can_tagged_qng = 0;
     asc_dvc->cfg->cmd_qng_enabled = 0;
     asc_dvc->dvc_cntl = ASC_DEF_DVC_CNTL;
     asc_dvc->init_sdtr = 0;
@@ -12950,10 +13940,12 @@ AscInitAscDvcVar(
     return (warn_code);
 }
 
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
 AscInitFromEEP(
                   ASC_DVC_VAR asc_ptr_type * asc_dvc
 )
+)
 {
     ASCEEP_CONFIG       eep_config_buf;
     ASCEEP_CONFIG       *eep_config;
@@ -13031,11 +14023,11 @@ AscInitFromEEP(
                 /* Indicate EEPROM-less board. */
                 eep_config->adapter_info[5] = 0xBB;
             } else {
-                write_eep = 1 ;
-                warn_code |= ASC_WARN_EEPROM_CHKSUM ;
+                write_eep = 1;
+                warn_code |= ASC_WARN_EEPROM_CHKSUM;
             }
     }
-    asc_dvc->cfg->sdtr_enable = eep_config->init_sdtr ;
+    asc_dvc->cfg->sdtr_enable = eep_config->init_sdtr;
     asc_dvc->cfg->disc_enable = eep_config->disc_enable;
     asc_dvc->cfg->cmd_qng_enabled = eep_config->use_cmd_qng;
     asc_dvc->cfg->isa_dma_speed = eep_config->isa_dma_speed;
@@ -13103,10 +14095,12 @@ AscInitFromEEP(
     return (warn_code);
 }
 
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
 AscInitMicroCodeVar(
                        ASC_DVC_VAR asc_ptr_type * asc_dvc
 )
+)
 {
     int                 i;
     ushort              warn_code;
@@ -13151,10 +14145,12 @@ AscInitMicroCodeVar(
     return (warn_code);
 }
 
-STATIC int ASC_INIT
+ASC_INITFUNC(
+STATIC int,
 AscTestExternalLram(
                        ASC_DVC_VAR asc_ptr_type * asc_dvc
 )
+)
 {
     PortAddr            iop_base;
     ushort              q_addr;
@@ -13176,11 +14172,13 @@ AscTestExternalLram(
     return (sta);
 }
 
-STATIC int ASC_INIT
+ASC_INITFUNC(
+STATIC int,
 AscWriteEEPCmdReg(
                      PortAddr iop_base,
                      uchar cmd_reg
 )
+)
 {
     uchar               read_back;
     int                 retry;
@@ -13199,11 +14197,13 @@ AscWriteEEPCmdReg(
     }
 }
 
-STATIC int ASC_INIT
+ASC_INITFUNC(
+STATIC int,
 AscWriteEEPDataReg(
                       PortAddr iop_base,
                       ushort data_reg
 )
+)
 {
     ushort              read_back;
     int                 retry;
@@ -13222,29 +14222,35 @@ AscWriteEEPDataReg(
     }
 }
 
-STATIC void ASC_INIT
+ASC_INITFUNC(
+STATIC void,
 AscWaitEEPRead(
                   void
 )
+)
 {
     DvcSleepMilliSecond(1);
     return;
 }
 
-STATIC void ASC_INIT
+ASC_INITFUNC(
+STATIC void,
 AscWaitEEPWrite(
                    void
 )
+)
 {
     DvcSleepMilliSecond(20);
     return;
 }
 
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
 AscReadEEPWord(
                   PortAddr iop_base,
                   uchar addr
 )
+)
 {
     ushort              read_wval;
     uchar               cmd_reg;
@@ -13259,12 +14265,14 @@ AscReadEEPWord(
     return (read_wval);
 }
 
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
 AscWriteEEPWord(
                    PortAddr iop_base,
                    uchar addr,
                    ushort word_val
 )
+)
 {
     ushort              read_wval;
 
@@ -13284,11 +14292,13 @@ AscWriteEEPWord(
     return (read_wval);
 }
 
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
 AscGetEEPConfig(
                    PortAddr iop_base,
                    ASCEEP_CONFIG * cfg_buf, ushort bus_type
 )
+)
 {
     ushort              wval;
     ushort              sum;
@@ -13323,11 +14333,13 @@ AscGetEEPConfig(
     return (sum);
 }
 
-STATIC int ASC_INIT
+ASC_INITFUNC(
+STATIC int,
 AscSetEEPConfigOnce(
                        PortAddr iop_base,
                        ASCEEP_CONFIG * cfg_buf, ushort bus_type
 )
+)
 {
     int                 n_error;
     ushort      *wbuf;
@@ -13378,11 +14390,13 @@ AscSetEEPConfigOnce(
     return (n_error);
 }
 
-STATIC int ASC_INIT
+ASC_INITFUNC(
+STATIC int,
 AscSetEEPConfig(
                    PortAddr iop_base,
                    ASCEEP_CONFIG * cfg_buf, ushort bus_type
 )
+)
 {
     int            retry;
     int            n_error;
@@ -13406,55 +14420,35 @@ AscAsyncFix(
                uchar tid_no,
                ASC_SCSI_INQUIRY *inq)
 {
-    uchar                dvc_type;
-    ASC_SCSI_BIT_ID_TYPE tid_bits;
+    uchar                       dvc_type;
+    ASC_SCSI_BIT_ID_TYPE        tid_bits;
 
     dvc_type = inq->byte0.peri_dvc_type;
     tid_bits = ASC_TIX_TO_TARGET_ID(tid_no);
 
-    if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ASYN_USE_SYN) {
-        if (!(asc_dvc->init_sdtr & tid_bits)) {
+    if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ASYN_USE_SYN)
+    {
+        if (!(asc_dvc->init_sdtr & tid_bits))
+        {
             if ((dvc_type == SCSI_TYPE_CDROM) &&
                 (AscCompareString((uchar *) inq->vendor_id,
-                    (uchar *) "HP ", 3) == 0)) {
+                    (uchar *) "HP ", 3) == 0))
+            {
                 asc_dvc->pci_fix_asyn_xfer_always |= tid_bits;
             }
             asc_dvc->pci_fix_asyn_xfer |= tid_bits;
             if ((dvc_type == SCSI_TYPE_PROC) ||
-                (dvc_type == SCSI_TYPE_SCANNER)) {
-                asc_dvc->pci_fix_asyn_xfer &= ~tid_bits;
-            }
-            if ((dvc_type == SCSI_TYPE_SASD) &&
-                (AscCompareString((uchar *) inq->vendor_id,
-                 (uchar *) "TANDBERG", 8) == 0) &&
-                (AscCompareString((uchar *) inq->product_id,
-                 (uchar *) " TDC 36", 7) == 0)) {
-                asc_dvc->pci_fix_asyn_xfer &= ~tid_bits;
-            }
-            if ((dvc_type == SCSI_TYPE_SASD) &&
-                (AscCompareString((uchar *) inq->vendor_id,
-                 (uchar *) "WANGTEK ", 8) == 0)) {
-                asc_dvc->pci_fix_asyn_xfer &= ~tid_bits;
-            }
-
-            if ((dvc_type == SCSI_TYPE_CDROM) &&
-                (AscCompareString((uchar *) inq->vendor_id,
-                 (uchar *) "NEC     ", 8) == 0) &&
-                (AscCompareString((uchar *) inq->product_id,
-                 (uchar *) "CD-ROM DRIVE    ", 16) == 0)) {
+                (dvc_type == SCSI_TYPE_SCANNER) ||
+                (dvc_type == SCSI_TYPE_CDROM) ||
+                (dvc_type == SCSI_TYPE_SASD))
+            {
                 asc_dvc->pci_fix_asyn_xfer &= ~tid_bits;
             }
 
-            if ((dvc_type == SCSI_TYPE_CDROM) &&
-                (AscCompareString((uchar *) inq->vendor_id,
-                 (uchar *) "YAMAHA", 6) == 0) &&
-                (AscCompareString((uchar *) inq->product_id,
-                 (uchar *) "CDR400", 6) == 0)) {
-                asc_dvc->pci_fix_asyn_xfer &= ~tid_bits;
-            }
-            if (asc_dvc->pci_fix_asyn_xfer & tid_bits) {
+            if (asc_dvc->pci_fix_asyn_xfer & tid_bits)
+            {
                 AscSetRunChipSynRegAtID(asc_dvc->iop_base, tid_no,
-                                        ASYN_SDTR_DATA_FIX_PCI_REV_AB);
+                    ASYN_SDTR_DATA_FIX_PCI_REV_AB);
             }
         }
     }
@@ -13718,299 +14712,666 @@ AscMemWordSetLram(
  * --- Adv Library Functions
  */
 
-/* a_qswap.h */
-STATIC unsigned char _adv_mcode_buf[] ASC_INITDATA = {
-  0x9C,  0xF0,  0x80,  0x01,  0x00,  0xF0,  0x44,  0x0A,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x72,  0x01,  0xD6,  0x11,  0x00,  0x00,  0x70,  0x01,
-  0x30,  0x01,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x90,  0x10,  0x2D,  0x03,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x48,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x01,  0x01,  0x01,  0x01,  0x01,  0x01,  0x01,  0x01,  0x01,  0x01,  0x01,  0x01,  0x01,  0x01,  0x01,  0x01,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x78,  0x56,  0x34,  0x12,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x04,  0xF7,  0x70,  0x01,  0x0C,  0x1C,  0x06,  0xF7,  0x02,  0x00,  0x00,  0xF2,  0xD6,  0x0A,
-  0x04,  0xF7,  0x70,  0x01,  0x06,  0xF7,  0x02,  0x00,  0x3E,  0x57,  0x3C,  0x56,  0x0C,  0x1C,  0x00,  0xFC,
-  0xA6,  0x00,  0x01,  0x58,  0xAA,  0x13,  0x20,  0xF0,  0xA6,  0x03,  0x06,  0xEC,  0xB9,  0x00,  0x0E,  0x47,
-  0x03,  0xE6,  0x10,  0x00,  0xCE,  0x45,  0x02,  0x13,  0x3E,  0x57,  0x06,  0xEA,  0xB9,  0x00,  0x47,  0x4B,
-  0x03,  0xF6,  0xE0,  0x00,  0x00,  0xF2,  0x68,  0x0A,  0x01,  0x48,  0x4E,  0x12,  0x03,  0xF6,  0xC0,  0x00,
-  0x00,  0xF2,  0x68,  0x0A,  0x41,  0x58,  0x03,  0xF6,  0xD0,  0x00,  0x00,  0xF2,  0x68,  0x0A,  0x49,  0x44,
-  0x59,  0xF0,  0x0A,  0x02,  0x03,  0xF6,  0xE0,  0x00,  0x00,  0xF2,  0x68,  0x0A,  0x44,  0x58,  0x00,  0xF2,
-  0xE2,  0x0D,  0x02,  0xCC,  0x4A,  0xE4,  0x01,  0x00,  0x55,  0xF0,  0x08,  0x03,  0x45,  0xF4,  0x02,  0x00,
-  0x83,  0x5A,  0x04,  0xCC,  0x01,  0x4A,  0x12,  0x12,  0x00,  0xF2,  0xE2,  0x0D,  0x00,  0xCD,  0x48,  0xE4,
-  0x01,  0x00,  0xE9,  0x13,  0x00,  0xF2,  0xC6,  0x0F,  0xFA,  0x10,  0x0E,  0x47,  0x03,  0xE6,  0x10,  0x00,
-  0xCE,  0x45,  0x02,  0x13,  0x3E,  0x57,  0xCE,  0x47,  0x97,  0x13,  0x04,  0xEC,  0xB4,  0x00,  0x00,  0xF2,
-  0xE2,  0x0D,  0x00,  0xCD,  0x48,  0xE4,  0x00,  0x00,  0x12,  0x12,  0x3E,  0x57,  0x06,  0xCC,  0x45,  0xF4,
-  0x02,  0x00,  0x83,  0x5A,  0x00,  0xCC,  0x00,  0xEA,  0xB4,  0x00,  0x92,  0x10,  0x00,  0xF0,  0x8C,  0x01,
-  0x43,  0xF0,  0x5C,  0x02,  0x44,  0xF0,  0x60,  0x02,  0x45,  0xF0,  0x64,  0x02,  0x46,  0xF0,  0x68,  0x02,
-  0x47,  0xF0,  0x6E,  0x02,  0x48,  0xF0,  0x9E,  0x02,  0xB9,  0x54,  0x62,  0x10,  0x00,  0x1C,  0x5A,  0x10,
-  0x02,  0x1C,  0x56,  0x10,  0x1E,  0x1C,  0x52,  0x10,  0x00,  0xF2,  0x1E,  0x11,  0x50,  0x10,  0x06,  0xFC,
-  0xA8,  0x00,  0x03,  0xF6,  0xBE,  0x00,  0x00,  0xF2,  0x4E,  0x0A,  0x8C,  0x10,  0x01,  0xF6,  0x01,  0x00,
-  0x01,  0xFA,  0xA8,  0x00,  0x00,  0xF2,  0x2C,  0x0B,  0x06,  0x10,  0xB9,  0x54,  0x01,  0xFA,  0xA8,  0x00,
-  0x03,  0xF6,  0xBE,  0x00,  0x00,  0xF2,  0x58,  0x0A,  0x01,  0xFC,  0xA8,  0x00,  0x20,  0x10,  0x58,  0x1C,
-  0x00,  0xF2,  0x1C,  0x0B,  0x5A,  0x1C,  0x01,  0xF6,  0x01,  0x00,  0x38,  0x54,  0x00,  0xFA,  0xA6,  0x00,
-  0x01,  0xFA,  0xA8,  0x00,  0x20,  0x1C,  0x00,  0xF0,  0x72,  0x01,  0x01,  0xF6,  0x01,  0x00,  0x38,  0x54,
-  0x00,  0xFA,  0xA6,  0x00,  0x01,  0xFA,  0xA8,  0x00,  0x20,  0x1C,  0x00,  0xF0,  0x80,  0x01,  0x03,  0xF6,
-  0xE0,  0x00,  0x00,  0xF2,  0x68,  0x0A,  0x01,  0x48,  0x0A,  0x13,  0x00,  0xF2,  0x38,  0x10,  0x00,  0xF2,
-  0x54,  0x0F,  0x24,  0x10,  0x03,  0xF6,  0xC0,  0x00,  0x00,  0xF2,  0x68,  0x0A,  0x02,  0xF6,  0xD0,  0x00,
-  0x02,  0x57,  0x03,  0x59,  0x01,  0xCC,  0x49,  0x44,  0x5B,  0xF0,  0x04,  0x03,  0x00,  0xF2,  0x9C,  0x0F,
-  0x00,  0xF0,  0x80,  0x01,  0x00,  0xF2,  0x14,  0x10,  0x0C,  0x1C,  0x02,  0x4B,  0xBF,  0x57,  0x9E,  0x43,
-  0x77,  0x57,  0x07,  0x4B,  0x20,  0xF0,  0xA6,  0x03,  0x40,  0x1C,  0x1E,  0xF0,  0x30,  0x03,  0x26,  0xF0,
-  0x2C,  0x03,  0xA0,  0xF0,  0x1A,  0x03,  0x11,  0xF0,  0xA6,  0x03,  0x12,  0x10,  0x9F,  0xF0,  0x3E,  0x03,
-  0x46,  0x1C,  0x82,  0xE7,  0x05,  0x00,  0x9E,  0xE7,  0x11,  0x00,  0x00,  0xF0,  0x06,  0x0A,  0x0C,  0x1C,
-  0x48,  0x1C,  0x46,  0x1C,  0x38,  0x54,  0x00,  0xEC,  0xBA,  0x00,  0x08,  0x44,  0x00,  0xEA,  0xBA,  0x00,
-  0x03,  0xF6,  0xC0,  0x00,  0x00,  0xF2,  0x68,  0x0A,  0x08,  0x44,  0x00,  0x4C,  0x82,  0xE7,  0x02,  0x00,
-  0x00,  0xF2,  0x12,  0x11,  0x00,  0xF2,  0x12,  0x11,  0x85,  0xF0,  0x70,  0x03,  0x00,  0xF2,  0x60,  0x0B,
-  0x06,  0xF0,  0x80,  0x03,  0x09,  0xF0,  0x24,  0x09,  0x1E,  0xF0,  0xFC,  0x09,  0x00,  0xF0,  0x02,  0x0A,
-  0x00,  0xFC,  0xBE,  0x00,  0x98,  0x57,  0x55,  0xF0,  0xAC,  0x04,  0x01,  0xE6,  0x0C,  0x00,  0x00,  0xF2,
-  0x4E,  0x0D,  0x00,  0xF2,  0x12,  0x11,  0x00,  0xF2,  0xBC,  0x11,  0x00,  0xF2,  0xC8,  0x11,  0x01,  0xF0,
-  0x7C,  0x02,  0x00,  0xF0,  0x8A,  0x02,  0x46,  0x1C,  0x0C,  0x1C,  0x67,  0x1B,  0xBF,  0x57,  0x77,  0x57,
-  0x02,  0x4B,  0x48,  0x1C,  0x32,  0x1C,  0x00,  0xF2,  0x92,  0x0D,  0x30,  0x1C,  0x96,  0xF0,  0xBC,  0x03,
-  0xB1,  0xF0,  0xC0,  0x03,  0x1E,  0xF0,  0xFC,  0x09,  0x85,  0xF0,  0x02,  0x0A,  0x00,  0xFC,  0xBE,  0x00,
-  0x98,  0x57,  0x14,  0x12,  0x01,  0xE6,  0x0C,  0x00,  0x00,  0xF2,  0x4E,  0x0D,  0x00,  0xF2,  0x12,  0x11,
-  0x01,  0xF0,  0x7C,  0x02,  0x00,  0xF0,  0x8A,  0x02,  0x03,  0xF6,  0xE0,  0x00,  0x00,  0xF2,  0x68,  0x0A,
-  0x01,  0x48,  0x55,  0xF0,  0x98,  0x04,  0x03,  0x82,  0x03,  0xFC,  0xA0,  0x00,  0x9B,  0x57,  0x40,  0x12,
-  0x69,  0x18,  0x00,  0xF2,  0x12,  0x11,  0x85,  0xF0,  0x42,  0x04,  0x69,  0x08,  0x00,  0xF2,  0x12,  0x11,
-  0x85,  0xF0,  0x02,  0x0A,  0x68,  0x08,  0x4C,  0x44,  0x28,  0x12,  0x44,  0x48,  0x03,  0xF6,  0xE0,  0x00,
-  0x00,  0xF2,  0x68,  0x0A,  0x45,  0x58,  0x00,  0xF2,  0xF6,  0x0D,  0x00,  0xCC,  0x01,  0x48,  0x55,  0xF0,
-  0x98,  0x04,  0x4C,  0x44,  0xEF,  0x13,  0x00,  0xF2,  0xC6,  0x0F,  0x00,  0xF2,  0x14,  0x10,  0x08,  0x10,
-  0x68,  0x18,  0x45,  0x5A,  0x00,  0xF2,  0xF6,  0x0D,  0x04,  0x80,  0x18,  0xE4,  0x10,  0x00,  0x28,  0x12,
-  0x01,  0xE6,  0x06,  0x00,  0x04,  0x80,  0x18,  0xE4,  0x01,  0x00,  0x04,  0x12,  0x01,  0xE6,  0x0D,  0x00,
-  0x00,  0xF2,  0x4E,  0x0D,  0x00,  0xF2,  0x12,  0x11,  0x04,  0xE6,  0x02,  0x00,  0x9E,  0xE7,  0x15,  0x00,
-  0x01,  0xF0,  0x1C,  0x0A,  0x00,  0xF0,  0x02,  0x0A,  0x69,  0x08,  0x05,  0x80,  0x48,  0xE4,  0x00,  0x00,
-  0x0C,  0x12,  0x00,  0xE6,  0x11,  0x00,  0x00,  0xEA,  0xB8,  0x00,  0x00,  0xF2,  0xB6,  0x10,  0x82,  0xE7,
-  0x02,  0x00,  0x1C,  0x90,  0x40,  0x5C,  0x00,  0x16,  0x01,  0xE6,  0x06,  0x00,  0x00,  0xF2,  0x4E,  0x0D,
-  0x01,  0xF0,  0x80,  0x01,  0x1E,  0xF0,  0x80,  0x01,  0x00,  0xF0,  0xA0,  0x04,  0x42,  0x5B,  0x06,  0xF7,
-  0x03,  0x00,  0x46,  0x59,  0xBF,  0x57,  0x77,  0x57,  0x01,  0xE6,  0x80,  0x00,  0x07,  0x80,  0x31,  0x44,
-  0x04,  0x80,  0x18,  0xE4,  0x20,  0x00,  0x56,  0x13,  0x20,  0x80,  0x48,  0xE4,  0x03,  0x00,  0x4E,  0x12,
-  0x00,  0xFC,  0xA2,  0x00,  0x98,  0x57,  0x55,  0xF0,  0x1C,  0x05,  0x31,  0xE4,  0x40,  0x00,  0x00,  0xFC,
-  0xA0,  0x00,  0x98,  0x57,  0x36,  0x12,  0x4C,  0x1C,  0x00,  0xF2,  0x12,  0x11,  0x89,  0x48,  0x00,  0xF2,
-  0x12,  0x11,  0x86,  0xF0,  0x2E,  0x05,  0x82,  0xE7,  0x06,  0x00,  0x1B,  0x80,  0x48,  0xE4,  0x22,  0x00,
-  0x5B,  0xF0,  0x0C,  0x05,  0x48,  0xE4,  0x20,  0x00,  0x59,  0xF0,  0x10,  0x05,  0x00,  0xE6,  0x20,  0x00,
-  0x09,  0x48,  0x00,  0xF2,  0x12,  0x11,  0x86,  0xF0,  0x2E,  0x05,  0x83,  0x80,  0x04,  0x10,  0x00,  0xF2,
-  0xA2,  0x0D,  0x00,  0xE6,  0x01,  0x00,  0x00,  0xEA,  0x26,  0x01,  0x01,  0xEA,  0x27,  0x01,  0x04,  0x80,
-  0x18,  0xE4,  0x10,  0x00,  0x36,  0x12,  0xB9,  0x54,  0x00,  0xF2,  0xF6,  0x0E,  0x01,  0xE6,  0x06,  0x00,
-  0x04,  0x80,  0x18,  0xE4,  0x01,  0x00,  0x04,  0x12,  0x01,  0xE6,  0x0D,  0x00,  0x00,  0xF2,  0x4E,  0x0D,
-  0x00,  0xF2,  0x12,  0x11,  0x00,  0xF2,  0xBC,  0x11,  0x00,  0xF2,  0xC8,  0x11,  0x04,  0xE6,  0x02,  0x00,
-  0x9E,  0xE7,  0x15,  0x00,  0x01,  0xF0,  0x1C,  0x0A,  0x00,  0xF0,  0x02,  0x0A,  0x00,  0xFC,  0x20,  0x01,
-  0x98,  0x57,  0x34,  0x12,  0x00,  0xFC,  0x24,  0x01,  0x98,  0x57,  0x2C,  0x13,  0xB9,  0x54,  0x00,  0xF2,
-  0xF6,  0x0E,  0x86,  0xF0,  0xA8,  0x05,  0x03,  0xF6,  0x01,  0x00,  0x00,  0xF2,  0x8C,  0x0E,  0x85,  0xF0,
-  0x9E,  0x05,  0x82,  0xE7,  0x03,  0x00,  0x00,  0xF2,  0x60,  0x0B,  0x82,  0xE7,  0x02,  0x00,  0x00,  0xFC,
-  0x24,  0x01,  0xB0,  0x57,  0x00,  0xFA,  0x24,  0x01,  0x00,  0xFC,  0x9E,  0x00,  0x98,  0x57,  0x5A,  0x12,
-  0x00,  0xFC,  0xB6,  0x00,  0x98,  0x57,  0x52,  0x13,  0x03,  0xE6,  0x0C,  0x00,  0x00,  0xFC,  0x9C,  0x00,
-  0x98,  0x57,  0x04,  0x13,  0x03,  0xE6,  0x19,  0x00,  0x05,  0xE6,  0x08,  0x00,  0x00,  0xF6,  0x00,  0x01,
-  0x00,  0x57,  0x00,  0x57,  0x03,  0x58,  0x00,  0xDC,  0x18,  0xF4,  0x00,  0x80,  0x04,  0x13,  0x05,  0xE6,
-  0x0F,  0x00,  0xB9,  0x54,  0x00,  0xF2,  0xF6,  0x0E,  0x86,  0xF0,  0x0A,  0x06,  0x00,  0xF2,  0xBA,  0x0E,
-  0x85,  0xF0,  0x00,  0x06,  0x82,  0xE7,  0x03,  0x00,  0x00,  0xF2,  0x60,  0x0B,  0x82,  0xE7,  0x02,  0x00,
-  0x00,  0xFC,  0xB6,  0x00,  0xB0,  0x57,  0x00,  0xFA,  0xB6,  0x00,  0x01,  0xF6,  0x01,  0x00,  0x00,  0xF2,
-  0xF6,  0x0E,  0x9C,  0x32,  0x4E,  0x1C,  0x32,  0x1C,  0x00,  0xF2,  0x92,  0x0D,  0x30,  0x1C,  0x82,  0xE7,
-  0x04,  0x00,  0xB1,  0xF0,  0x22,  0x06,  0x0A,  0xF0,  0x3E,  0x06,  0x05,  0xF0,  0xD6,  0x06,  0x06,  0xF0,
-  0xDC,  0x06,  0x09,  0xF0,  0x24,  0x09,  0x1E,  0xF0,  0xFC,  0x09,  0x00,  0xF0,  0x02,  0x0A,  0x04,  0x80,
-  0x18,  0xE4,  0x20,  0x00,  0x30,  0x12,  0x09,  0xE7,  0x03,  0x00,  0x00,  0xF2,  0x12,  0x11,  0x21,  0x80,
-  0x18,  0xE4,  0xE0,  0x00,  0x09,  0x48,  0x00,  0xF2,  0x12,  0x11,  0x09,  0xE7,  0x00,  0x00,  0x00,  0xF2,
-  0x12,  0x11,  0x09,  0xE7,  0x00,  0x00,  0x00,  0xF2,  0x12,  0x11,  0x99,  0xA4,  0x00,  0xF2,  0x12,  0x11,
-  0x09,  0xE7,  0x00,  0x00,  0x9A,  0x10,  0x04,  0x80,  0x18,  0xE4,  0x02,  0x00,  0x34,  0x12,  0x09,  0xE7,
-  0x1B,  0x00,  0x00,  0xF2,  0x12,  0x11,  0x21,  0x80,  0x18,  0xE4,  0xE0,  0x00,  0x09,  0x48,  0x00,  0xF2,
-  0x12,  0x11,  0x09,  0xE7,  0x00,  0x00,  0x00,  0xF2,  0x12,  0x11,  0x09,  0xE7,  0x00,  0x00,  0x00,  0xF2,
-  0x12,  0x11,  0x09,  0xE7,  0x01,  0x00,  0x00,  0xF2,  0x12,  0x11,  0x09,  0xE7,  0x00,  0x00,  0x00,  0xF0,
-  0x0C,  0x09,  0xBB,  0x55,  0x9A,  0x81,  0x03,  0xF7,  0x20,  0x00,  0x09,  0x6F,  0x93,  0x45,  0x55,  0xF0,
-  0xE2,  0x06,  0xB1,  0xF0,  0xC2,  0x06,  0x0A,  0xF0,  0xBA,  0x06,  0x09,  0xF0,  0x24,  0x09,  0x1E,  0xF0,
-  0xFC,  0x09,  0x00,  0xF0,  0x02,  0x0A,  0x00,  0xF2,  0x60,  0x0B,  0x47,  0x10,  0x09,  0xE7,  0x08,  0x00,
-  0x41,  0x10,  0x05,  0x80,  0x48,  0xE4,  0x00,  0x00,  0x1E,  0x12,  0x00,  0xE6,  0x11,  0x00,  0x00,  0xEA,
-  0xB8,  0x00,  0x00,  0xF2,  0xB6,  0x10,  0x2C,  0x90,  0xAE,  0x90,  0x08,  0x50,  0x8A,  0x50,  0x38,  0x54,
-  0x1F,  0x40,  0x00,  0xF2,  0xB4,  0x0D,  0x08,  0x10,  0x08,  0x90,  0x8A,  0x90,  0x30,  0x50,  0xB2,  0x50,
-  0x9C,  0x32,  0x0C,  0x92,  0x8E,  0x92,  0x38,  0x54,  0x04,  0x80,  0x30,  0xE4,  0x08,  0x00,  0x04,  0x40,
-  0x0C,  0x1C,  0x00,  0xF6,  0x03,  0x00,  0xB1,  0xF0,  0x26,  0x07,  0x9E,  0xF0,  0x3A,  0x07,  0x01,  0x48,
-  0x55,  0xF0,  0xFC,  0x09,  0x0C,  0x1C,  0x10,  0x44,  0xED,  0x10,  0x0B,  0xF0,  0x5E,  0x07,  0x0C,  0xF0,
-  0x62,  0x07,  0x05,  0xF0,  0x52,  0x07,  0x06,  0xF0,  0x58,  0x07,  0x09,  0xF0,  0x24,  0x09,  0x00,  0xF0,
-  0x02,  0x0A,  0x00,  0xF2,  0x60,  0x0B,  0xCF,  0x10,  0x09,  0xE7,  0x08,  0x00,  0xC9,  0x10,  0x2E,  0x1C,
-  0x02,  0x10,  0x2C,  0x1C,  0xAA,  0xF0,  0x64,  0x07,  0xAC,  0xF0,  0x72,  0x07,  0x40,  0x10,  0x34,  0x1C,
-  0xF3,  0x10,  0xAD,  0xF0,  0x7C,  0x07,  0xC8,  0x10,  0x36,  0x1C,  0xE9,  0x10,  0x2B,  0xF0,  0x82,  0x08,
-  0x6B,  0x18,  0x18,  0xF4,  0x00,  0xFE,  0x20,  0x12,  0x01,  0x58,  0xD2,  0xF0,  0x82,  0x08,  0x76,  0x18,
-  0x18,  0xF4,  0x03,  0x00,  0xEC,  0x12,  0x00,  0xFC,  0x22,  0x01,  0x18,  0xF4,  0x01,  0x00,  0xE2,  0x12,
-  0x0B,  0xF0,  0x64,  0x07,  0x0C,  0xF0,  0x64,  0x07,  0x36,  0x1C,  0x34,  0x1C,  0xB7,  0x10,  0x38,  0x54,
-  0xB9,  0x54,  0x84,  0x80,  0x19,  0xE4,  0x20,  0x00,  0xB2,  0x13,  0x85,  0x80,  0x81,  0x48,  0x66,  0x12,
-  0x04,  0x80,  0x18,  0xE4,  0x08,  0x00,  0x58,  0x13,  0x1F,  0x80,  0x08,  0x44,  0xC8,  0x44,  0x9F,  0x12,
-  0x1F,  0x40,  0x34,  0x91,  0xB6,  0x91,  0x44,  0x55,  0xE5,  0x55,  0x02,  0xEC,  0xB8,  0x00,  0x02,  0x49,
-  0xBB,  0x55,  0x82,  0x81,  0xC0,  0x55,  0x48,  0xF4,  0x0F,  0x00,  0x5A,  0xF0,  0x1A,  0x08,  0x4A,  0xE4,
-  0x17,  0x00,  0xD5,  0xF0,  0xFA,  0x07,  0x02,  0xF6,  0x0F,  0x00,  0x02,  0xF4,  0x02,  0x00,  0x02,  0xEA,
-  0xB8,  0x00,  0x04,  0x91,  0x86,  0x91,  0x02,  0x4B,  0x2C,  0x90,  0x08,  0x50,  0x2E,  0x90,  0x0A,  0x50,
-  0x2C,  0x51,  0xAE,  0x51,  0x00,  0xF2,  0xB6,  0x10,  0x38,  0x54,  0x00,  0xF2,  0xB4,  0x0D,  0x56,  0x10,
-  0x34,  0x91,  0xB6,  0x91,  0x0C,  0x10,  0x04,  0x80,  0x18,  0xE4,  0x08,  0x00,  0x41,  0x12,  0x0C,  0x91,
-  0x8E,  0x91,  0x04,  0x80,  0x18,  0xE4,  0xF7,  0x00,  0x04,  0x40,  0x30,  0x90,  0xB2,  0x90,  0x36,  0x10,
-  0x02,  0x80,  0x48,  0xE4,  0x10,  0x00,  0x31,  0x12,  0x82,  0xE7,  0x10,  0x00,  0x84,  0x80,  0x19,  0xE4,
-  0x20,  0x00,  0x10,  0x13,  0x0C,  0x90,  0x8E,  0x90,  0x5D,  0xF0,  0x78,  0x07,  0x0C,  0x58,  0x8D,  0x58,
-  0x00,  0xF0,  0x64,  0x07,  0x38,  0x54,  0xB9,  0x54,  0x19,  0x80,  0xF1,  0x10,  0x3A,  0x55,  0x19,  0x81,
-  0xBB,  0x55,  0x10,  0x90,  0x92,  0x90,  0x10,  0x58,  0x91,  0x58,  0x14,  0x59,  0x95,  0x59,  0x00,  0xF0,
-  0x64,  0x07,  0x04,  0x80,  0x18,  0xE4,  0x20,  0x00,  0x06,  0x12,  0x6C,  0x19,  0x19,  0x41,  0x7C,  0x10,
-  0x6C,  0x19,  0x0C,  0x51,  0xED,  0x19,  0x8E,  0x51,  0x6B,  0x18,  0x18,  0xF4,  0x00,  0xFF,  0x02,  0x13,
-  0x6A,  0x10,  0x01,  0x58,  0xD2,  0xF0,  0xC0,  0x08,  0x76,  0x18,  0x18,  0xF4,  0x03,  0x00,  0x0A,  0x12,
-  0x00,  0xFC,  0x22,  0x01,  0x18,  0xF4,  0x01,  0x00,  0x06,  0x13,  0x9E,  0xE7,  0x16,  0x00,  0x4C,  0x10,
-  0xD1,  0xF0,  0xCA,  0x08,  0x9E,  0xE7,  0x17,  0x00,  0x42,  0x10,  0xD0,  0xF0,  0xD4,  0x08,  0x9E,  0xE7,
-  0x19,  0x00,  0x38,  0x10,  0xCF,  0xF0,  0xDE,  0x08,  0x9E,  0xE7,  0x20,  0x00,  0x2E,  0x10,  0xCE,  0xF0,
-  0xE8,  0x08,  0x9E,  0xE7,  0x21,  0x00,  0x24,  0x10,  0xCD,  0xF0,  0xF2,  0x08,  0x9E,  0xE7,  0x22,  0x00,
-  0x1A,  0x10,  0xCC,  0xF0,  0x04,  0x09,  0x84,  0x80,  0x19,  0xE4,  0x04,  0x00,  0x06,  0x12,  0x9E,  0xE7,
-  0x12,  0x00,  0x08,  0x10,  0xCB,  0xF0,  0x0C,  0x09,  0x9E,  0xE7,  0x24,  0x00,  0xB1,  0xF0,  0x0C,  0x09,
-  0x05,  0xF0,  0x1E,  0x09,  0x09,  0xF0,  0x24,  0x09,  0x1E,  0xF0,  0xFC,  0x09,  0xE4,  0x10,  0x00,  0xF2,
-  0x60,  0x0B,  0xE9,  0x10,  0x9C,  0x32,  0x82,  0xE7,  0x20,  0x00,  0x32,  0x1C,  0xE9,  0x09,  0x00,  0xF2,
-  0x12,  0x11,  0x85,  0xF0,  0x02,  0x0A,  0x69,  0x08,  0x01,  0xF0,  0x44,  0x09,  0x1E,  0xF0,  0xFC,  0x09,
-  0x00,  0xF0,  0x38,  0x09,  0x30,  0x44,  0x06,  0x12,  0x9E,  0xE7,  0x42,  0x00,  0xB8,  0x10,  0x04,  0xF6,
-  0x01,  0x00,  0xB3,  0x45,  0x74,  0x12,  0x04,  0x80,  0x18,  0xE4,  0x20,  0x00,  0x22,  0x13,  0x4B,  0xE4,
-  0x02,  0x00,  0x36,  0x12,  0x4B,  0xE4,  0x28,  0x00,  0xAC,  0x13,  0x00,  0xF2,  0xBC,  0x11,  0x00,  0xF2,
-  0xC8,  0x11,  0x03,  0xF6,  0xD0,  0x00,  0xFA,  0x14,  0x82,  0xE7,  0x01,  0x00,  0x00,  0xF0,  0x80,  0x01,
-  0x9E,  0xE7,  0x44,  0x00,  0x4B,  0xE4,  0x02,  0x00,  0x06,  0x12,  0x03,  0xE6,  0x02,  0x00,  0x76,  0x10,
-  0x00,  0xF2,  0xA2,  0x0D,  0x03,  0xE6,  0x02,  0x00,  0x6C,  0x10,  0x00,  0xF2,  0xA2,  0x0D,  0x19,  0x82,
-  0x34,  0x46,  0x0A,  0x13,  0x03,  0xE6,  0x02,  0x00,  0x9E,  0xE7,  0x43,  0x00,  0x68,  0x10,  0x04,  0x80,
-  0x30,  0xE4,  0x20,  0x00,  0x04,  0x40,  0x00,  0xF2,  0xBC,  0x11,  0x00,  0xF2,  0xC8,  0x11,  0x82,  0xE7,
-  0x01,  0x00,  0x06,  0xF7,  0x02,  0x00,  0x00,  0xF0,  0x08,  0x03,  0x04,  0x80,  0x18,  0xE4,  0x20,  0x00,
-  0x06,  0x12,  0x03,  0xE6,  0x02,  0x00,  0x3E,  0x10,  0x04,  0x80,  0x18,  0xE4,  0x02,  0x00,  0x3A,  0x12,
-  0x04,  0x80,  0x18,  0xE4,  0xFD,  0x00,  0x04,  0x40,  0x1C,  0x1C,  0x9D,  0xF0,  0xEA,  0x09,  0x1C,  0x1C,
-  0x9D,  0xF0,  0xF0,  0x09,  0xC1,  0x10,  0x9E,  0xE7,  0x13,  0x00,  0x0A,  0x10,  0x9E,  0xE7,  0x41,  0x00,
-  0x04,  0x10,  0x9E,  0xE7,  0x24,  0x00,  0x00,  0xFC,  0xBE,  0x00,  0x98,  0x57,  0xD5,  0xF0,  0x8A,  0x02,
-  0x04,  0xE6,  0x04,  0x00,  0x06,  0x10,  0x04,  0xE6,  0x04,  0x00,  0x9D,  0x41,  0x1C,  0x42,  0x9F,  0xE7,
-  0x00,  0x00,  0x06,  0xF7,  0x02,  0x00,  0x03,  0xF6,  0xE0,  0x00,  0x3C,  0x14,  0x44,  0x58,  0x45,  0x58,
-  0x00,  0xF2,  0xF6,  0x0D,  0x00,  0xF2,  0x7E,  0x10,  0x00,  0xF2,  0xC6,  0x0F,  0x3C,  0x14,  0x1E,  0x1C,
-  0x00,  0xF0,  0x80,  0x01,  0x12,  0x1C,  0x22,  0x1C,  0xD2,  0x14,  0x00,  0xF0,  0x72,  0x01,  0x83,  0x59,
-  0x03,  0xDC,  0x73,  0x57,  0x80,  0x5D,  0x00,  0x16,  0x83,  0x59,  0x03,  0xDC,  0x38,  0x54,  0x70,  0x57,
-  0x33,  0x54,  0x3B,  0x54,  0x80,  0x5D,  0x00,  0x16,  0x03,  0x57,  0x83,  0x59,  0x38,  0x54,  0x00,  0xCC,
-  0x00,  0x16,  0x03,  0x57,  0x83,  0x59,  0x00,  0x4C,  0x00,  0x16,  0x02,  0x80,  0x48,  0xE4,  0x01,  0x00,
-  0x0E,  0x12,  0x48,  0xE4,  0x05,  0x00,  0x08,  0x12,  0x00,  0xF2,  0xBC,  0x11,  0x00,  0xF2,  0xC8,  0x11,
-  0xC1,  0x5A,  0x3A,  0x55,  0x02,  0xEC,  0xB5,  0x00,  0x45,  0x59,  0x00,  0xF2,  0xF6,  0x0D,  0x83,  0x58,
-  0x30,  0xE7,  0x00,  0x00,  0x10,  0x4D,  0x30,  0xE7,  0x40,  0x00,  0x10,  0x4F,  0x38,  0x90,  0xBA,  0x90,
-  0x10,  0x5C,  0x80,  0x5C,  0x83,  0x5A,  0x10,  0x4E,  0x04,  0xEA,  0xB5,  0x00,  0x43,  0x5B,  0x03,  0xF4,
-  0xE0,  0x00,  0x83,  0x59,  0x04,  0xCC,  0x01,  0x4A,  0x0A,  0x12,  0x45,  0x5A,  0x00,  0xF2,  0xF6,  0x0D,
-  0x00,  0xF2,  0x38,  0x10,  0x00,  0x16,  0x08,  0x1C,  0x00,  0xFC,  0xAC,  0x00,  0x06,  0x58,  0x67,  0x18,
-  0x18,  0xF4,  0x8F,  0xE1,  0x01,  0xFC,  0xAE,  0x00,  0x19,  0xF4,  0x70,  0x1E,  0xB0,  0x54,  0x07,  0x58,
-  0x00,  0xFC,  0xB0,  0x00,  0x08,  0x58,  0x00,  0xFC,  0xB2,  0x00,  0x09,  0x58,  0x0A,  0x1C,  0x00,  0xE6,
-  0x0F,  0x00,  0x00,  0xEA,  0xB9,  0x00,  0x38,  0x54,  0x00,  0xFA,  0x24,  0x01,  0x00,  0xFA,  0xB6,  0x00,
-  0x18,  0x1C,  0x14,  0x1C,  0x10,  0x1C,  0x32,  0x1C,  0x12,  0x1C,  0x00,  0x16,  0x3E,  0x57,  0x0C,  0x14,
-  0x0E,  0x47,  0x07,  0xE6,  0x10,  0x00,  0xCE,  0x47,  0xF5,  0x13,  0x00,  0x16,  0x00,  0xF2,  0xA2,  0x0D,
-  0x02,  0x4B,  0x03,  0xF6,  0xE0,  0x00,  0x00,  0xF2,  0x68,  0x0A,  0x01,  0x48,  0x20,  0x12,  0x44,  0x58,
-  0x45,  0x58,  0x9E,  0xE7,  0x15,  0x00,  0x9C,  0xE7,  0x04,  0x00,  0x00,  0xF2,  0xF6,  0x0D,  0x00,  0xF2,
-  0x7E,  0x10,  0x00,  0xF2,  0xC6,  0x0F,  0x00,  0xF2,  0x7A,  0x0A,  0x1E,  0x1C,  0xD5,  0x10,  0x00,  0x16,
-  0x69,  0x08,  0x48,  0xE4,  0x04,  0x00,  0x64,  0x12,  0x48,  0xE4,  0x02,  0x00,  0x20,  0x12,  0x48,  0xE4,
-  0x03,  0x00,  0x1A,  0x12,  0x48,  0xE4,  0x08,  0x00,  0x14,  0x12,  0x48,  0xE4,  0x01,  0x00,  0xF0,  0x12,
-  0x48,  0xE4,  0x07,  0x00,  0x12,  0x12,  0x01,  0xE6,  0x07,  0x00,  0x00,  0xF2,  0x4E,  0x0D,  0x00,  0xF2,
-  0x12,  0x11,  0x05,  0xF0,  0x60,  0x0B,  0x00,  0x16,  0x00,  0xE6,  0x01,  0x00,  0x00,  0xEA,  0x99,  0x00,
-  0x02,  0x80,  0x48,  0xE4,  0x03,  0x00,  0xE7,  0x12,  0x48,  0xE4,  0x06,  0x00,  0xE1,  0x12,  0x01,  0xE6,
-  0x06,  0x00,  0x00,  0xF2,  0x4E,  0x0D,  0x00,  0xF2,  0x12,  0x11,  0x04,  0xE6,  0x02,  0x00,  0x9E,  0xE7,
-  0x15,  0x00,  0x01,  0xF0,  0x1C,  0x0A,  0x00,  0xF0,  0x02,  0x0A,  0x00,  0x16,  0x02,  0x80,  0x48,  0xE4,
-  0x10,  0x00,  0x1C,  0x12,  0x82,  0xE7,  0x08,  0x00,  0x3C,  0x56,  0x03,  0x82,  0x00,  0xF2,  0xE2,  0x0D,
-  0x30,  0xE7,  0x08,  0x00,  0x04,  0xF7,  0x70,  0x01,  0x06,  0xF7,  0x02,  0x00,  0x00,  0xF0,  0x80,  0x01,
-  0x6C,  0x19,  0xED,  0x19,  0x5D,  0xF0,  0xD4,  0x0B,  0x44,  0x55,  0xE5,  0x55,  0x59,  0xF0,  0x52,  0x0C,
-  0x04,  0x55,  0xA5,  0x55,  0x1F,  0x80,  0x01,  0xEC,  0xB8,  0x00,  0x82,  0x48,  0x82,  0x80,  0x49,  0x44,
-  0x2E,  0x13,  0x01,  0xEC,  0xB8,  0x00,  0x41,  0xE4,  0x02,  0x00,  0x01,  0xEA,  0xB8,  0x00,  0x49,  0xE4,
-  0x11,  0x00,  0x59,  0xF0,  0x2E,  0x0C,  0x01,  0xE6,  0x17,  0x00,  0x01,  0xEA,  0xB8,  0x00,  0x02,  0x4B,
-  0x88,  0x90,  0xAC,  0x50,  0x8A,  0x90,  0xAE,  0x50,  0x01,  0xEC,  0xB8,  0x00,  0x82,  0x48,  0x82,  0x80,
-  0x10,  0x44,  0x02,  0x4B,  0x1F,  0x40,  0xC0,  0x44,  0x00,  0xF2,  0xB4,  0x0D,  0x04,  0x55,  0xA5,  0x55,
-  0x9F,  0x10,  0x0C,  0x51,  0x8E,  0x51,  0x30,  0x90,  0xB2,  0x90,  0x00,  0x56,  0xA1,  0x56,  0x30,  0x50,
-  0xB2,  0x50,  0x34,  0x90,  0xB6,  0x90,  0x40,  0x56,  0xE1,  0x56,  0x34,  0x50,  0xB6,  0x50,  0x65,  0x10,
-  0xB1,  0xF0,  0x70,  0x0C,  0x85,  0xF0,  0xCA,  0x0B,  0xE9,  0x09,  0x4B,  0xE4,  0x03,  0x00,  0x78,  0x12,
-  0x4B,  0xE4,  0x02,  0x00,  0x01,  0x13,  0xB1,  0xF0,  0x86,  0x0C,  0x85,  0xF0,  0xCA,  0x0B,  0x69,  0x08,
-  0x48,  0xE4,  0x03,  0x00,  0xD5,  0xF0,  0x86,  0x0B,  0x00,  0xF2,  0x12,  0x11,  0x85,  0xF0,  0xCA,  0x0B,
-  0xE8,  0x09,  0x3C,  0x56,  0x00,  0xFC,  0x20,  0x01,  0x98,  0x57,  0x02,  0x13,  0xBB,  0x45,  0x4B,  0xE4,
-  0x00,  0x00,  0x08,  0x12,  0x03,  0xE6,  0x01,  0x00,  0x04,  0xF6,  0x00,  0x80,  0xA8,  0x14,  0xD2,  0x14,
-  0x30,  0x1C,  0x02,  0x80,  0x48,  0xE4,  0x03,  0x00,  0x10,  0x13,  0x00,  0xFC,  0xB6,  0x00,  0x98,  0x57,
-  0x02,  0x13,  0x4C,  0x1C,  0x3E,  0x1C,  0x00,  0xF0,  0x8E,  0x0B,  0x00,  0xFC,  0x24,  0x01,  0xB0,  0x57,
-  0x00,  0xFA,  0x24,  0x01,  0x4C,  0x1C,  0x3E,  0x1C,  0x00,  0xF2,  0x12,  0x11,  0x86,  0xF0,  0x8E,  0x0B,
-  0x00,  0xF2,  0x8C,  0x0E,  0x00,  0xF0,  0x8E,  0x0B,  0xB1,  0xF0,  0xF8,  0x0C,  0x85,  0xF0,  0x86,  0x0B,
-  0x69,  0x08,  0x48,  0xE4,  0x01,  0x00,  0xD5,  0xF0,  0x86,  0x0B,  0xFC,  0x14,  0x42,  0x58,  0x6C,  0x14,
-  0x80,  0x14,  0x30,  0x1C,  0x4A,  0xF4,  0x02,  0x00,  0x55,  0xF0,  0x86,  0x0B,  0x4A,  0xF4,  0x01,  0x00,
-  0x0E,  0x12,  0x02,  0x80,  0x48,  0xE4,  0x03,  0x00,  0x06,  0x13,  0x3E,  0x1C,  0x00,  0xF0,  0x8E,  0x0B,
-  0x00,  0xFC,  0xB6,  0x00,  0xB0,  0x57,  0x00,  0xFA,  0xB6,  0x00,  0x4C,  0x1C,  0x3E,  0x1C,  0x00,  0xF2,
-  0x12,  0x11,  0x86,  0xF0,  0x8E,  0x0B,  0x00,  0xF2,  0xBA,  0x0E,  0x00,  0xF0,  0x8E,  0x0B,  0x4C,  0x1C,
-  0xB1,  0xF0,  0x50,  0x0D,  0x85,  0xF0,  0x5C,  0x0D,  0x69,  0x08,  0xF3,  0x10,  0x86,  0xF0,  0x64,  0x0D,
-  0x4E,  0x1C,  0x89,  0x48,  0x00,  0x16,  0x00,  0xF6,  0x00,  0x01,  0x00,  0x57,  0x00,  0x57,  0x03,  0x58,
-  0x00,  0xDC,  0x18,  0xF4,  0xFF,  0x7F,  0x30,  0x56,  0x00,  0x5C,  0x00,  0x16,  0x00,  0xF6,  0x00,  0x01,
-  0x00,  0x57,  0x00,  0x57,  0x03,  0x58,  0x00,  0xDC,  0x18,  0xF4,  0x00,  0x80,  0x30,  0x56,  0x00,  0x5C,
-  0x00,  0x16,  0x00,  0xF6,  0x00,  0x01,  0x00,  0x57,  0x00,  0x57,  0x03,  0x58,  0x00,  0xDC,  0x0B,  0x58,
-  0x00,  0x16,  0x03,  0xF6,  0x24,  0x01,  0x00,  0xF2,  0x58,  0x0A,  0x03,  0xF6,  0xB6,  0x00,  0x00,  0xF2,
-  0x58,  0x0A,  0x00,  0x16,  0x02,  0xEC,  0xB8,  0x00,  0x02,  0x49,  0x18,  0xF4,  0xFF,  0x00,  0x00,  0x54,
-  0x00,  0x54,  0x00,  0x54,  0x00,  0xF4,  0x08,  0x00,  0xE1,  0x18,  0x80,  0x54,  0x03,  0x58,  0x00,  0xDD,
-  0x01,  0xDD,  0x02,  0xDD,  0x03,  0xDC,  0x02,  0x4B,  0x30,  0x50,  0xB2,  0x50,  0x34,  0x51,  0xB6,  0x51,
-  0x00,  0x16,  0x45,  0x5A,  0x1D,  0xF4,  0xFF,  0x00,  0x85,  0x56,  0x85,  0x56,  0x85,  0x56,  0x05,  0xF4,
-  0x02,  0x12,  0x83,  0x5A,  0x00,  0x16,  0x1D,  0xF4,  0xFF,  0x00,  0x85,  0x56,  0x85,  0x56,  0x85,  0x56,
-  0x05,  0xF4,  0x00,  0x12,  0x83,  0x5A,  0x00,  0x16,  0x38,  0x54,  0xBB,  0x55,  0x3C,  0x56,  0xBD,  0x56,
-  0x00,  0xF2,  0x12,  0x11,  0x85,  0xF0,  0x82,  0x0E,  0xE9,  0x09,  0xC1,  0x59,  0x00,  0xF2,  0x12,  0x11,
-  0x85,  0xF0,  0x82,  0x0E,  0xE8,  0x0A,  0x83,  0x55,  0x83,  0x55,  0x4B,  0xF4,  0x90,  0x01,  0x5C,  0xF0,
-  0x36,  0x0E,  0xBD,  0x56,  0x40,  0x10,  0x4B,  0xF4,  0x30,  0x00,  0x59,  0xF0,  0x48,  0x0E,  0x01,  0xF6,
-  0x0C,  0x00,  0x00,  0xF6,  0x01,  0x00,  0x2E,  0x10,  0x02,  0xFC,  0x9C,  0x00,  0x9A,  0x57,  0x14,  0x13,
-  0x4B,  0xF4,  0x64,  0x00,  0x59,  0xF0,  0x64,  0x0E,  0x03,  0xF6,  0x64,  0x00,  0x01,  0xF6,  0x19,  0x00,
-  0x00,  0xF6,  0x01,  0x00,  0x43,  0xF4,  0x33,  0x00,  0x56,  0xF0,  0x76,  0x0E,  0x04,  0xF4,  0x00,  0x01,
-  0x43,  0xF4,  0x19,  0x00,  0xF3,  0x10,  0xB4,  0x56,  0xC3,  0x58,  0x02,  0xFC,  0x9E,  0x00,  0x9A,  0x57,
-  0x08,  0x13,  0x3C,  0x56,  0x00,  0xF6,  0x02,  0x00,  0x00,  0x16,  0x00,  0x16,  0x09,  0xE7,  0x01,  0x00,
-  0x00,  0xF2,  0x12,  0x11,  0x86,  0xF0,  0xB8,  0x0E,  0x09,  0xE7,  0x02,  0x00,  0x00,  0xF2,  0x12,  0x11,
-  0x86,  0xF0,  0xB8,  0x0E,  0x09,  0xE7,  0x03,  0x00,  0x00,  0xF2,  0x12,  0x11,  0x86,  0xF0,  0xB8,  0x0E,
-  0x4E,  0x1C,  0x89,  0x49,  0x00,  0xF2,  0x12,  0x11,  0x00,  0x16,  0x09,  0xE7,  0x01,  0x00,  0x00,  0xF2,
-  0x12,  0x11,  0x86,  0xF0,  0xF2,  0x0E,  0x09,  0xE7,  0x03,  0x00,  0x00,  0xF2,  0x12,  0x11,  0x86,  0xF0,
-  0xF2,  0x0E,  0x09,  0xE7,  0x01,  0x00,  0x00,  0xF2,  0x12,  0x11,  0x86,  0xF0,  0xF2,  0x0E,  0x89,  0x49,
-  0x00,  0xF2,  0x12,  0x11,  0x86,  0xF0,  0xF2,  0x0E,  0x4E,  0x1C,  0x89,  0x4A,  0x00,  0xF2,  0x12,  0x11,
-  0x00,  0x16,  0x3C,  0x56,  0x00,  0x16,  0x00,  0xEC,  0x26,  0x01,  0x48,  0xE4,  0x01,  0x00,  0x1E,  0x13,
-  0x38,  0x44,  0x00,  0xEA,  0x26,  0x01,  0x49,  0xF4,  0x00,  0x00,  0x04,  0x12,  0x4E,  0x1C,  0x02,  0x10,
-  0x4C,  0x1C,  0x01,  0xEC,  0x27,  0x01,  0x89,  0x48,  0x00,  0xF2,  0x12,  0x11,  0x02,  0x14,  0x00,  0x16,
-  0x85,  0xF0,  0x52,  0x0F,  0x38,  0x54,  0x00,  0xEA,  0x99,  0x00,  0x00,  0xF2,  0x60,  0x0B,  0x02,  0x80,
-  0x48,  0xE4,  0x06,  0x00,  0x1C,  0x13,  0x00,  0xEC,  0x99,  0x00,  0x48,  0xE4,  0x01,  0x00,  0x0A,  0x12,
-  0x04,  0x80,  0x30,  0xE4,  0x01,  0x00,  0x04,  0x40,  0x08,  0x10,  0x04,  0x80,  0x18,  0xE4,  0xFE,  0x00,
-  0x04,  0x40,  0x00,  0x16,  0x02,  0xF6,  0xE0,  0x00,  0x02,  0x57,  0x03,  0x59,  0x01,  0xCC,  0x81,  0x48,
-  0x22,  0x12,  0x00,  0x4E,  0x83,  0x5A,  0x90,  0x4C,  0x20,  0xE7,  0x00,  0x00,  0xC3,  0x58,  0x1B,  0xF4,
-  0xFF,  0x00,  0x83,  0x55,  0x83,  0x55,  0x83,  0x55,  0x03,  0xF4,  0x00,  0x12,  0x8B,  0x55,  0x83,  0x59,
-  0x00,  0x4E,  0x00,  0x16,  0x00,  0x4E,  0x02,  0xF6,  0xF0,  0x00,  0x02,  0x57,  0x03,  0x59,  0x00,  0x4E,
-  0x83,  0x5A,  0x30,  0xE7,  0x00,  0x00,  0x20,  0xE7,  0x00,  0x00,  0x00,  0x16,  0x02,  0xF6,  0xF0,  0x00,
-  0x02,  0x57,  0x03,  0x59,  0x01,  0xCC,  0x00,  0x4E,  0x83,  0x5A,  0x30,  0xE7,  0x00,  0x00,  0x80,  0x4C,
-  0xC3,  0x58,  0x1B,  0xF4,  0xFF,  0x00,  0x83,  0x55,  0x83,  0x55,  0x83,  0x55,  0x03,  0xF4,  0x00,  0x12,
-  0x83,  0x59,  0x00,  0x4E,  0x00,  0x16,  0x03,  0xF6,  0xE0,  0x00,  0x03,  0x57,  0x83,  0x59,  0x3A,  0x55,
-  0x02,  0xCC,  0x45,  0x5A,  0x00,  0xF2,  0xF6,  0x0D,  0xC0,  0x5A,  0x40,  0x5C,  0x38,  0x54,  0x00,  0xCD,
-  0x01,  0xCC,  0x4A,  0x46,  0x0A,  0x13,  0x83,  0x59,  0x00,  0x4C,  0x01,  0x48,  0x16,  0x13,  0x0C,  0x10,
-  0xC5,  0x58,  0x00,  0xF2,  0xF6,  0x0D,  0x00,  0x4C,  0x01,  0x48,  0x08,  0x13,  0x05,  0xF6,  0xF0,  0x00,
-  0x05,  0x57,  0x08,  0x10,  0x45,  0x58,  0x00,  0xF2,  0xF6,  0x0D,  0x8D,  0x56,  0x83,  0x5A,  0x80,  0x4C,
-  0x05,  0x17,  0x00,  0x16,  0x02,  0x4B,  0x06,  0xF7,  0x04,  0x00,  0x62,  0x0B,  0x03,  0x82,  0x00,  0xF2,
-  0xE2,  0x0D,  0x02,  0x80,  0x00,  0x4C,  0x45,  0xF4,  0x02,  0x00,  0x52,  0x14,  0x06,  0xF7,  0x02,  0x00,
-  0x06,  0x14,  0x00,  0xF2,  0x54,  0x0F,  0x00,  0x16,  0x02,  0x4B,  0x01,  0xF6,  0xFF,  0x00,  0x38,  0x1C,
-  0x05,  0xF4,  0x04,  0x00,  0x83,  0x5A,  0x18,  0xDF,  0x19,  0xDF,  0x1D,  0xF7,  0x3C,  0x00,  0xB8,  0xF0,
-  0x4E,  0x10,  0x9C,  0x14,  0x01,  0x48,  0x1C,  0x13,  0x0E,  0xF7,  0x3C,  0x00,  0x03,  0xF7,  0x04,  0x00,
-  0xAF,  0x19,  0x03,  0x42,  0x45,  0xF4,  0x02,  0x00,  0x83,  0x5A,  0x02,  0xCC,  0x02,  0x41,  0x45,  0xF4,
-  0x02,  0x00,  0x00,  0x16,  0x91,  0x44,  0xD5,  0xF0,  0x3E,  0x10,  0x00,  0xF0,  0x9E,  0x02,  0x01,  0xF6,
-  0xFF,  0x00,  0x38,  0x1C,  0x05,  0xF4,  0x04,  0x00,  0x83,  0x5A,  0x18,  0xDF,  0x19,  0xDF,  0x0E,  0xF7,
-  0x3C,  0x00,  0x03,  0xF7,  0x04,  0x00,  0x0F,  0x79,  0x1C,  0xF7,  0x3C,  0x00,  0xB8,  0xF0,  0x9C,  0x10,
-  0x4E,  0x14,  0x01,  0x48,  0x06,  0x13,  0x45,  0xF4,  0x04,  0x00,  0x00,  0x16,  0x91,  0x44,  0xD5,  0xF0,
-  0x82,  0x10,  0x00,  0xF0,  0x9E,  0x02,  0x02,  0xF6,  0xFF,  0x00,  0x38,  0x1C,  0x2C,  0xBC,  0xAE,  0xBC,
-  0xE2,  0x08,  0x00,  0xEC,  0xB8,  0x00,  0x02,  0x48,  0x1D,  0xF7,  0x80,  0x00,  0xB8,  0xF0,  0xCC,  0x10,
-  0x1E,  0x14,  0x01,  0x48,  0x0E,  0x13,  0x0E,  0xF7,  0x80,  0x00,  0x38,  0x54,  0x03,  0x58,  0xAF,  0x19,
-  0x82,  0x48,  0x00,  0x16,  0x82,  0x48,  0x12,  0x45,  0xD5,  0xF0,  0xBA,  0x10,  0x00,  0xF0,  0x9E,  0x02,
-  0x39,  0xF0,  0xF8,  0x10,  0x38,  0x44,  0x00,  0x16,  0x7E,  0x18,  0x18,  0xF4,  0x03,  0x00,  0x04,  0x13,
-  0x61,  0x18,  0x00,  0x16,  0x38,  0x1C,  0x00,  0xFC,  0x22,  0x01,  0x18,  0xF4,  0x01,  0x00,  0xF1,  0x12,
-  0xE3,  0x10,  0x30,  0x44,  0x30,  0x44,  0x30,  0x44,  0xB1,  0xF0,  0x18,  0x11,  0x00,  0x16,  0x3E,  0x57,
-  0x03,  0xF6,  0xE0,  0x00,  0x03,  0x57,  0x83,  0x59,  0x04,  0xCC,  0x01,  0x4A,  0x6A,  0x12,  0x45,  0x5A,
-  0x00,  0xF2,  0xF6,  0x0D,  0x02,  0x4B,  0x70,  0x14,  0x34,  0x13,  0x02,  0x80,  0x48,  0xE4,  0x08,  0x00,
-  0x18,  0x12,  0x9C,  0xE7,  0x02,  0x00,  0x9E,  0xE7,  0x15,  0x00,  0x00,  0xF2,  0xC6,  0x0F,  0x00,  0xF2,
-  0x7A,  0x0A,  0x1E,  0x1C,  0x01,  0xF6,  0x01,  0x00,  0x00,  0x16,  0x30,  0xE4,  0x10,  0x00,  0x04,  0x40,
-  0x00,  0xF2,  0xE2,  0x0D,  0x20,  0xE7,  0x01,  0x00,  0x01,  0xF6,  0x01,  0x00,  0x00,  0x16,  0x04,  0xDC,
-  0x01,  0x4A,  0x24,  0x12,  0x45,  0x5A,  0x00,  0xF2,  0xF6,  0x0D,  0x43,  0x5B,  0x06,  0xEC,  0x98,  0x00,
-  0x00,  0xF2,  0x38,  0x10,  0xC6,  0x59,  0x20,  0x14,  0x0A,  0x13,  0x00,  0xF2,  0xC6,  0x0F,  0x00,  0xF2,
-  0x14,  0x10,  0xA7,  0x10,  0x83,  0x5A,  0xD7,  0x10,  0x0E,  0x47,  0x07,  0xE6,  0x10,  0x00,  0xCE,  0x47,
-  0x5A,  0xF0,  0x20,  0x11,  0xB9,  0x54,  0x00,  0x16,  0x14,  0x90,  0x96,  0x90,  0x02,  0xFC,  0xA8,  0x00,
-  0x03,  0xFC,  0xAA,  0x00,  0x48,  0x55,  0x02,  0x13,  0xC9,  0x55,  0x00,  0x16,  0x00,  0xEC,  0xBA,  0x00,
-  0x10,  0x44,  0x00,  0xEA,  0xBA,  0x00,  0x00,  0x16,  0x03,  0xF6,  0xC0,  0x00,  0x00,  0xF2,  0x68,  0x0A,
-  0x10,  0x44,  0x00,  0x4C,  0x00,  0x16
-};
-
-unsigned short _adv_mcode_size ASC_INITDATA =
-    sizeof(_adv_mcode_buf); /* 0x11D6 */
-unsigned long  _adv_mcode_chksum ASC_INITDATA = 0x03494981UL;
+/* a_mcode.h */
+STATIC unsigned char _adv_asc3550_buf[] = {
+  0x00,  0x00,  0x00,  0xf2,  0x00,  0xf0,  0x00,  0x16,  0x00,  0xfc,  0x48,  0xe4,  0x01,  0x00,  0x01,  0xf6,
+  0x00,  0xf6,  0x18,  0xe4,  0x0a,  0x19,  0x18,  0x80,  0x02,  0x00,  0xff,  0xff,  0x03,  0xf6,  0x00,  0xfa,
+  0xff,  0x00,  0x82,  0xe7,  0x9e,  0xe7,  0x01,  0xfa,  0x06,  0x0e,  0x09,  0xe7,  0x00,  0xea,  0x01,  0xe6,
+  0x03,  0x00,  0x08,  0x00,  0x18,  0xf4,  0x55,  0xf0,  0x3e,  0x01,  0x3e,  0x57,  0x04,  0x00,  0x1e,  0xf0,
+  0x85,  0xf0,  0x00,  0xe6,  0x00,  0xec,  0x32,  0xf0,  0x86,  0xf0,  0xa4,  0x0c,  0xd0,  0x01,  0xd5,  0xf0,
+  0xf6,  0x18,  0x38,  0x54,  0x98,  0x57,  0xbc,  0x00,  0xb1,  0xf0,  0xb4,  0x00,  0x01,  0xfc,  0x02,  0x13,
+  0x03,  0xfc,  0x9e,  0x0c,  0x00,  0x57,  0x01,  0xf0,  0x03,  0xe6,  0x0c,  0x1c,  0x10,  0x00,  0x18,  0x40,
+  0x30,  0x12,  0x3e,  0x1c,  0xbd,  0x00,  0xe0,  0x00,  0x02,  0x48,  0x02,  0x80,  0x3c,  0x00,  0x4e,  0x01,
+  0x66,  0x15,  0x6c,  0x01,  0x6e,  0x01,  0xbb,  0x00,  0xda,  0x12,  0x00,  0x4e,  0x01,  0x01,  0x01,  0xea,
+  0x08,  0x12,  0x30,  0xe4,  0x6a,  0x0f,  0xa8,  0x0c,  0xae,  0x0f,  0xb6,  0x00,  0xb9,  0x54,  0x00,  0x80,
+  0x04,  0x12,  0x06,  0xf7,  0x24,  0x01,  0x28,  0x01,  0x32,  0x00,  0x3c,  0x01,  0x3c,  0x56,  0x3e,  0x00,
+  0x4b,  0xe4,  0x4c,  0x1c,  0x68,  0x01,  0x6a,  0x01,  0x70,  0x01,  0x72,  0x01,  0x74,  0x01,  0x76,  0x01,
+  0x78,  0x01,  0x00,  0x01,  0x02,  0xee,  0x02,  0xfc,  0x03,  0x58,  0x03,  0xf7,  0x04,  0x80,  0x05,  0xfc,
+  0x08,  0x44,  0x09,  0xf0,  0x0a,  0x15,  0x10,  0x44,  0x1b,  0x80,  0x20,  0x01,  0x38,  0x1c,  0x40,  0x00,
+  0x4b,  0xf4,  0x4e,  0x1c,  0x5b,  0xf0,  0x5d,  0xf0,  0x80,  0x00,  0xaa,  0x00,  0xaa,  0x14,  0xb6,  0x08,
+  0xb8,  0x0f,  0xbb,  0x55,  0xbd,  0x56,  0xbe,  0x00,  0xc0,  0x00,  0x00,  0x4c,  0x00,  0xdc,  0x02,  0x4a,
+  0x05,  0xf0,  0x05,  0xf8,  0x06,  0x13,  0x08,  0x13,  0x0c,  0x00,  0x0e,  0x47,  0x0e,  0xf7,  0x0f,  0x00,
+  0x19,  0x00,  0x20,  0x00,  0x2a,  0x01,  0x32,  0x1c,  0x36,  0x00,  0x38,  0x12,  0x3c,  0x0b,  0x45,  0x5a,
+  0x56,  0x14,  0x59,  0xf0,  0x62,  0x0a,  0x69,  0x08,  0x83,  0x59,  0xae,  0x17,  0xb8,  0xf0,  0xba,  0x0f,
+  0xba,  0x17,  0xf0,  0x00,  0xf6,  0x0d,  0x02,  0xfa,  0x03,  0xfa,  0x04,  0x10,  0x04,  0xea,  0x04,  0xf6,
+  0x04,  0xfc,  0x05,  0x00,  0x06,  0x00,  0x06,  0x12,  0x0a,  0x10,  0x0b,  0xf0,  0x0c,  0xf0,  0x12,  0x10,
+  0x30,  0x1c,  0x33,  0x00,  0x34,  0x00,  0x38,  0x44,  0x40,  0x5c,  0x4a,  0xe4,  0x5a,  0x14,  0x62,  0x1a,
+  0x64,  0x0a,  0x68,  0x08,  0x68,  0x54,  0x83,  0x55,  0x83,  0x5a,  0x91,  0x44,  0x98,  0x12,  0x9a,  0x16,
+  0xa4,  0x00,  0xb0,  0x57,  0xb5,  0x00,  0xba,  0x00,  0xce,  0x45,  0xd0,  0x00,  0xe1,  0x00,  0xe7,  0x00,
+  0xec,  0x0d,  0x00,  0x54,  0x01,  0x48,  0x01,  0x58,  0x02,  0x10,  0x02,  0xe6,  0x03,  0xa1,  0x04,  0x13,
+  0x05,  0xe6,  0x06,  0x0b,  0x06,  0x83,  0x06,  0xf0,  0x07,  0x00,  0x0a,  0x00,  0x0a,  0x12,  0x0a,  0xf0,
+  0x0c,  0x04,  0x0c,  0x10,  0x0c,  0x12,  0x0e,  0x13,  0x10,  0x10,  0x12,  0x1c,  0x17,  0x00,  0x18,  0x0e,
+  0x19,  0xe4,  0x1a,  0x10,  0x1c,  0x00,  0x1c,  0x12,  0x1c,  0x14,  0x1d,  0xf7,  0x1e,  0x13,  0x20,  0x1c,
+  0x20,  0xe7,  0x22,  0x01,  0x26,  0x01,  0x2a,  0x12,  0x30,  0xe7,  0x41,  0x58,  0x43,  0x48,  0x44,  0x55,
+  0x46,  0x1c,  0x4e,  0xe4,  0x5c,  0xf0,  0x72,  0x02,  0x74,  0x03,  0x77,  0x57,  0x88,  0x12,  0x89,  0x48,
+  0x92,  0x13,  0x99,  0x00,  0x9b,  0x00,  0x9c,  0x32,  0x9e,  0x00,  0xa8,  0x00,  0xaa,  0x12,  0xb9,  0x00,
+  0xba,  0x06,  0xbf,  0x57,  0xc0,  0x01,  0xc0,  0x08,  0xc2,  0x01,  0xfe,  0x9c,  0xf0,  0x26,  0x02,  0xfe,
+  0xc6,  0x0c,  0xff,  0x10,  0x00,  0x00,  0xfc,  0xfe,  0x18,  0x19,  0x00,  0xfa,  0xfe,  0x80,  0x01,  0xff,
+  0x03,  0x00,  0x00,  0x2f,  0xfe,  0x01,  0x05,  0xff,  0x40,  0x00,  0x00,  0x0d,  0xff,  0x09,  0x00,  0x00,
+  0xff,  0x08,  0x01,  0x01,  0xff,  0x10,  0xff,  0xff,  0xff,  0x1f,  0x00,  0x00,  0xff,  0x10,  0xff,  0xff,
+  0xff,  0x0f,  0x00,  0x00,  0xfe,  0x78,  0x56,  0xfe,  0x34,  0x12,  0xff,  0x21,  0x00,  0x00,  0xfe,  0x04,
+  0xf7,  0xfa,  0x35,  0x51,  0x0c,  0x01,  0xfe,  0xb6,  0x0e,  0xfe,  0x04,  0xf7,  0xfa,  0x51,  0x0c,  0x1d,
+  0x35,  0xfe,  0x3d,  0xf0,  0xfe,  0xf8,  0x01,  0xfe,  0x20,  0xf0,  0xd0,  0x04,  0x55,  0x50,  0x02,  0xfe,
+  0xe2,  0x0c,  0x01,  0xfe,  0x42,  0x0d,  0xfe,  0xe9,  0x12,  0x02,  0xfe,  0x04,  0x03,  0xfe,  0x28,  0x1c,
+  0x04,  0xfe,  0xa6,  0x00,  0xfe,  0xdd,  0x12,  0x4e,  0x13,  0xfe,  0xa6,  0x00,  0xc3,  0xfe,  0x48,  0xf0,
+  0xfe,  0x7c,  0x02,  0xfe,  0x49,  0xf0,  0xfe,  0x96,  0x02,  0xfe,  0x4a,  0xf0,  0xfe,  0xb4,  0x02,  0xfe,
+  0x46,  0xf0,  0xfe,  0x46,  0x02,  0xfe,  0x47,  0xf0,  0xfe,  0x4c,  0x02,  0xfe,  0x43,  0xf0,  0xfe,  0x3a,
+  0x02,  0xfe,  0x44,  0xf0,  0xfe,  0x3e,  0x02,  0xfe,  0x45,  0xf0,  0xfe,  0x42,  0x02,  0x07,  0x0c,  0x9d,
+  0x07,  0x06,  0x13,  0xb8,  0x02,  0x26,  0xfe,  0x00,  0x1c,  0xfe,  0xf1,  0x10,  0xfe,  0x02,  0x1c,  0xfe,
+  0xed,  0x10,  0xfe,  0x1e,  0x1c,  0xfe,  0xe9,  0x10,  0x01,  0xfe,  0x0e,  0x17,  0xfe,  0xe7,  0x10,  0xfe,
+  0x06,  0xfc,  0xf5,  0x0e,  0x7b,  0x01,  0xc0,  0x02,  0x26,  0x17,  0x54,  0x47,  0xba,  0x01,  0xfe,  0x2c,
+  0x0f,  0x0e,  0x7b,  0x01,  0x9a,  0xfe,  0xbd,  0x10,  0x0e,  0x7b,  0x01,  0x9a,  0xfe,  0xad,  0x10,  0xfe,
+  0x16,  0x1c,  0xfe,  0x58,  0x1c,  0x07,  0x06,  0x13,  0xb8,  0x35,  0x1f,  0x26,  0xfe,  0x3d,  0xf0,  0xfe,
+  0xf8,  0x01,  0x27,  0xfe,  0x8a,  0x02,  0xfe,  0x5a,  0x1c,  0xd5,  0xfe,  0x14,  0x1c,  0x17,  0xfe,  0x30,
+  0x00,  0x47,  0xba,  0x01,  0xfe,  0x1c,  0x0f,  0x07,  0x06,  0x13,  0xb8,  0x02,  0xfc,  0x22,  0x2b,  0x05,
+  0x10,  0x2f,  0xfe,  0x69,  0x10,  0x07,  0x06,  0x13,  0xb8,  0xfe,  0x04,  0xec,  0x2b,  0x08,  0x2b,  0x07,
+  0x3a,  0x1d,  0x01,  0x40,  0x7f,  0xfe,  0x05,  0xf6,  0xf5,  0x01,  0xfe,  0x40,  0x16,  0x0b,  0x49,  0x89,
+  0x37,  0x11,  0x43,  0x1d,  0xca,  0x08,  0x1c,  0x07,  0x3f,  0x01,  0x6a,  0x02,  0x26,  0x0e,  0x3b,  0x01,
+  0x14,  0x05,  0x10,  0xd3,  0x08,  0x1c,  0x07,  0x3f,  0x01,  0x76,  0xfe,  0x28,  0x10,  0x0e,  0xbd,  0x01,
+  0x14,  0xe5,  0x0e,  0x7c,  0x01,  0x14,  0xfe,  0x49,  0x54,  0x72,  0xfe,  0x12,  0x03,  0x08,  0x1c,  0x07,
+  0x3f,  0x01,  0x6a,  0x02,  0x26,  0x35,  0x7f,  0xfe,  0x02,  0xe8,  0x2d,  0xf9,  0xfe,  0x9e,  0x43,  0xed,
+  0xfe,  0x07,  0x4b,  0xfe,  0x20,  0xf0,  0xd0,  0xfe,  0x40,  0x1c,  0x1f,  0xec,  0xfe,  0x26,  0xf0,  0xfe,
+  0x70,  0x03,  0xfe,  0xa0,  0xf0,  0xfe,  0x5e,  0x03,  0xfe,  0x11,  0xf0,  0xd0,  0xfe,  0x0e,  0x10,  0xfe,
+  0x9f,  0xf0,  0xfe,  0x7e,  0x03,  0xe8,  0x12,  0xfe,  0x11,  0x00,  0x02,  0x4b,  0x35,  0xfe,  0x48,  0x1c,
+  0xe8,  0x1f,  0xec,  0x33,  0xec,  0xfe,  0x82,  0xf0,  0xfe,  0x84,  0x03,  0x29,  0x22,  0xbb,  0x68,  0x16,
+  0xbb,  0x0e,  0x7c,  0x01,  0x14,  0x68,  0x7d,  0x08,  0x1c,  0x07,  0x3f,  0x01,  0x40,  0x11,  0x3b,  0x08,
+  0x3b,  0x07,  0x99,  0x01,  0x6a,  0xf3,  0x11,  0xfe,  0xe4,  0x00,  0x2c,  0xfe,  0xca,  0x03,  0x1f,  0x31,
+  0x20,  0xfe,  0xda,  0x03,  0x01,  0x4a,  0xcb,  0xfe,  0xea,  0x03,  0x69,  0x8e,  0xcf,  0xfe,  0xaa,  0x06,
+  0x02,  0x25,  0x04,  0x7b,  0x2a,  0x1b,  0xfe,  0x1c,  0x05,  0x17,  0x84,  0x01,  0x38,  0x01,  0x95,  0x01,
+  0x98,  0x33,  0xfe,  0x5c,  0x02,  0x02,  0xeb,  0xe8,  0x35,  0x51,  0x18,  0xfe,  0x67,  0x1b,  0xf9,  0xed,
+  0xfe,  0x48,  0x1c,  0x8b,  0x01,  0xee,  0xa8,  0xfe,  0x96,  0xf0,  0xfe,  0x24,  0x04,  0x2c,  0xfe,  0x28,
+  0x04,  0x33,  0x26,  0x0e,  0x3b,  0x01,  0x14,  0x05,  0x10,  0x1b,  0xfe,  0x08,  0x05,  0x3c,  0x92,  0x9e,
+  0x2d,  0x81,  0x6d,  0x1f,  0x31,  0x20,  0x25,  0x04,  0x7b,  0x2a,  0xfe,  0x10,  0x12,  0x17,  0x84,  0x01,
+  0x38,  0x33,  0xfe,  0x5c,  0x02,  0x02,  0xeb,  0x30,  0xfe,  0xa0,  0x00,  0xfe,  0x9b,  0x57,  0xfe,  0x5e,
+  0x12,  0x0b,  0x09,  0x06,  0xfe,  0x56,  0x12,  0x23,  0x28,  0x93,  0x01,  0x0a,  0x81,  0x6d,  0x20,  0xfe,
+  0xd8,  0x04,  0x23,  0x28,  0x93,  0x01,  0x0a,  0x20,  0x25,  0x23,  0x28,  0xb1,  0xfe,  0x4c,  0x44,  0xfe,
+  0x32,  0x12,  0x56,  0xfe,  0x44,  0x48,  0x08,  0xd6,  0xfe,  0x4c,  0x54,  0x72,  0xfe,  0x08,  0x05,  0x7f,
+  0x9e,  0x2d,  0xfe,  0x06,  0x80,  0xfe,  0x48,  0x47,  0xfe,  0x48,  0x13,  0x3d,  0x05,  0xfe,  0xcc,  0x00,
+  0xfe,  0x40,  0x13,  0x0b,  0x09,  0x06,  0x8d,  0xfe,  0x06,  0x10,  0x23,  0x28,  0xb1,  0x0b,  0x09,  0x36,
+  0xdb,  0x17,  0xa2,  0x0b,  0x09,  0x06,  0x50,  0x17,  0xfe,  0x0d,  0x00,  0x01,  0x38,  0x33,  0xfe,  0x86,
+  0x0c,  0x02,  0x25,  0x39,  0x11,  0xfe,  0xe6,  0x00,  0xfe,  0x1c,  0x90,  0xac,  0x03,  0x17,  0xa2,  0x01,
+  0x38,  0x33,  0x26,  0x1f,  0x26,  0x02,  0xfe,  0x10,  0x05,  0xfe,  0x42,  0x5b,  0x51,  0x18,  0xfe,  0x46,
+  0x59,  0xf9,  0xed,  0x17,  0x74,  0xfe,  0x07,  0x80,  0xfe,  0x31,  0x44,  0x0b,  0x09,  0x0c,  0xfe,  0x78,
+  0x13,  0xfe,  0x20,  0x80,  0x05,  0x18,  0xfe,  0x70,  0x12,  0x6c,  0x09,  0x06,  0xfe,  0x60,  0x13,  0x04,
+  0xfe,  0xa2,  0x00,  0x2a,  0x1b,  0xfe,  0xa8,  0x05,  0xfe,  0x31,  0xe4,  0x6f,  0x6c,  0x09,  0x0c,  0xfe,
+  0x4a,  0x13,  0x04,  0xfe,  0xa0,  0x00,  0x2a,  0xfe,  0x42,  0x12,  0x59,  0x2c,  0xfe,  0x68,  0x05,  0x1f,
+  0x31,  0xef,  0x01,  0x0a,  0x24,  0xfe,  0xc0,  0x05,  0x11,  0xfe,  0xe3,  0x00,  0x29,  0x6c,  0xfe,  0x4a,
+  0xf0,  0xfe,  0x92,  0x05,  0xfe,  0x49,  0xf0,  0xfe,  0x8c,  0x05,  0xd1,  0x21,  0xfe,  0x21,  0x00,  0xa4,
+  0x21,  0xfe,  0x22,  0x00,  0x9d,  0x21,  0x89,  0xfe,  0x09,  0x48,  0x01,  0x0a,  0x24,  0xfe,  0xc0,  0x05,
+  0xfe,  0xe2,  0x08,  0x6c,  0x09,  0xda,  0x50,  0x01,  0xb6,  0x21,  0x06,  0x16,  0xe2,  0x47,  0xfe,  0x27,
+  0x01,  0x0b,  0x09,  0x36,  0xe3,  0x4e,  0x01,  0xae,  0x17,  0xa2,  0x0b,  0x09,  0x06,  0x50,  0x17,  0xfe,
+  0x0d,  0x00,  0x01,  0x38,  0x01,  0x95,  0x01,  0x98,  0x33,  0xfe,  0x86,  0x0c,  0x02,  0x25,  0x04,  0xfe,
+  0x9c,  0x00,  0x2a,  0xfe,  0x3e,  0x12,  0x04,  0x52,  0x2a,  0xfe,  0x36,  0x13,  0x4e,  0x01,  0xae,  0x24,
+  0xfe,  0x38,  0x06,  0x0e,  0x06,  0x6c,  0x09,  0x19,  0xfe,  0x02,  0x12,  0x79,  0x01,  0xfe,  0xf0,  0x13,
+  0x20,  0xfe,  0x2e,  0x06,  0x11,  0xbe,  0x01,  0x4a,  0x11,  0xfe,  0xe5,  0x00,  0x04,  0x52,  0xb9,  0x0f,
+  0x52,  0x04,  0xf4,  0x2a,  0xfe,  0x62,  0x12,  0x04,  0x4d,  0x2a,  0xfe,  0x5a,  0x13,  0x01,  0xfe,  0x60,
+  0x18,  0x01,  0xfe,  0xb2,  0x18,  0xe6,  0xc8,  0x19,  0x08,  0x61,  0xff,  0x02,  0x00,  0x57,  0x64,  0x7e,
+  0x1a,  0x4f,  0xc7,  0xc8,  0x87,  0x4e,  0x01,  0xae,  0x24,  0xfe,  0xa2,  0x06,  0x6c,  0x09,  0x1e,  0xa3,
+  0x7a,  0x0e,  0x54,  0x01,  0xfe,  0x1e,  0x14,  0x20,  0xfe,  0x98,  0x06,  0x11,  0xbe,  0x01,  0x4a,  0x11,
+  0xfe,  0xe5,  0x00,  0x04,  0x4d,  0xb9,  0x0f,  0x4d,  0x07,  0x06,  0x01,  0xae,  0xf3,  0x71,  0x8b,  0x01,
+  0xee,  0xa8,  0x11,  0xfe,  0xe2,  0x00,  0x2c,  0xf8,  0x1f,  0x31,  0xcf,  0xfe,  0xd6,  0x06,  0x80,  0xfe,
+  0x74,  0x07,  0xcb,  0xfe,  0x7c,  0x07,  0x69,  0x8e,  0x02,  0x25,  0x0b,  0x09,  0x0c,  0xfe,  0x2e,  0x12,
+  0x15,  0x18,  0x01,  0x0a,  0x15,  0x00,  0x01,  0x0a,  0x15,  0x00,  0x01,  0x0a,  0x15,  0x00,  0x01,  0x0a,
+  0xfe,  0x99,  0xa4,  0x01,  0x0a,  0x15,  0x00,  0x02,  0xfe,  0x3a,  0x08,  0x66,  0x09,  0x1e,  0x8d,  0x0b,
+  0x09,  0x1e,  0xfe,  0x30,  0x13,  0x15,  0xfe,  0x1b,  0x00,  0x01,  0x0a,  0x15,  0x00,  0x01,  0x0a,  0x15,
+  0x00,  0x01,  0x0a,  0x15,  0x00,  0x01,  0x0a,  0x15,  0x06,  0x01,  0x0a,  0x15,  0x00,  0x02,  0xc9,  0x79,
+  0xfe,  0x9a,  0x81,  0x65,  0x89,  0xfe,  0x09,  0x6f,  0xfe,  0x93,  0x45,  0x1b,  0xfe,  0x84,  0x07,  0x2c,
+  0xfe,  0x5c,  0x07,  0x1f,  0x31,  0xcf,  0xfe,  0x54,  0x07,  0x69,  0x8e,  0x80,  0xfe,  0x74,  0x07,  0x02,
+  0x25,  0x01,  0x4a,  0x02,  0xf8,  0x15,  0x19,  0x02,  0xf8,  0xfe,  0x9c,  0xf7,  0xfe,  0xf0,  0x07,  0xfe,
+  0x2c,  0x90,  0xfe,  0xae,  0x90,  0x73,  0xfe,  0xd2,  0x07,  0x0f,  0x5c,  0x13,  0x5d,  0x0b,  0x49,  0x6f,
+  0x37,  0x01,  0xfe,  0xf6,  0x17,  0x05,  0x10,  0x82,  0xfe,  0x83,  0xe7,  0x88,  0xa4,  0xfe,  0x03,  0x40,
+  0x0b,  0x49,  0x74,  0x37,  0x01,  0xb7,  0xab,  0xfe,  0x1f,  0x40,  0x16,  0x60,  0x01,  0xf6,  0xfe,  0x08,
+  0x50,  0xfe,  0x8a,  0x50,  0xfe,  0x34,  0x51,  0xfe,  0xb6,  0x51,  0xfe,  0x08,  0x90,  0xfe,  0x8a,  0x90,
+  0x0f,  0x5a,  0x13,  0x5b,  0xfe,  0x0c,  0x90,  0xfe,  0x8e,  0x90,  0xfe,  0x28,  0x50,  0xfe,  0xaa,  0x50,
+  0x0f,  0x41,  0x13,  0x42,  0xfe,  0x4a,  0x10,  0x0b,  0x09,  0x6f,  0xe3,  0xfe,  0x2c,  0x90,  0xfe,  0xae,
+  0x90,  0x0f,  0x5c,  0x13,  0x5d,  0x0b,  0x09,  0x74,  0xc7,  0x01,  0xb7,  0xfe,  0x1f,  0x80,  0x16,  0x60,
+  0xfe,  0x34,  0x90,  0xfe,  0xb6,  0x90,  0x0f,  0x5e,  0x13,  0x5f,  0xfe,  0x08,  0x90,  0xfe,  0x8a,  0x90,
+  0x0f,  0x5a,  0x13,  0x5b,  0xfe,  0x28,  0x90,  0xfe,  0xaa,  0x90,  0x0f,  0x41,  0x13,  0x42,  0x0f,  0x3e,
+  0x13,  0x57,  0x0b,  0x49,  0x19,  0x37,  0x35,  0x08,  0xa1,  0x2c,  0xfe,  0x50,  0x08,  0xfe,  0x9e,  0xf0,
+  0xfe,  0x64,  0x08,  0xc2,  0x1b,  0x31,  0x35,  0x6b,  0xfe,  0xed,  0x10,  0xa5,  0xfe,  0x88,  0x08,  0xa6,
+  0xfe,  0xa4,  0x08,  0x80,  0xfe,  0x7c,  0x08,  0xcb,  0xfe,  0x82,  0x08,  0x69,  0x8e,  0x02,  0x25,  0x01,
+  0x4a,  0xfe,  0xc9,  0x10,  0x15,  0x19,  0xfe,  0xc9,  0x10,  0x66,  0x09,  0x06,  0xfe,  0x10,  0x12,  0x66,
+  0x09,  0x0c,  0x48,  0x0b,  0x09,  0x0c,  0xfe,  0x66,  0x12,  0xfe,  0x2e,  0x1c,  0xa7,  0x66,  0x09,  0x06,
+  0x48,  0x66,  0x09,  0x0c,  0xfe,  0x52,  0x12,  0xfe,  0x2c,  0x1c,  0xfe,  0xaa,  0xf0,  0xfe,  0x24,  0x09,
+  0xfe,  0xac,  0xf0,  0xfe,  0xc4,  0x08,  0xfe,  0x92,  0x10,  0xfe,  0x34,  0x1c,  0xfe,  0xf3,  0x10,  0xfe,
+  0xad,  0xf0,  0xfe,  0xd0,  0x08,  0x02,  0xfe,  0x32,  0x0a,  0xfe,  0x36,  0x1c,  0xfe,  0xe7,  0x10,  0xfe,
+  0x2b,  0xf0,  0xb0,  0xfe,  0x6b,  0x18,  0x1a,  0xfe,  0x00,  0xfe,  0xdb,  0xc3,  0xfe,  0xd2,  0xf0,  0xb0,
+  0xfe,  0x76,  0x18,  0x1a,  0x18,  0x1b,  0xb0,  0x04,  0xe1,  0x1a,  0x06,  0x1b,  0xb0,  0xa5,  0x77,  0xa6,
+  0x77,  0xfe,  0x34,  0x1c,  0xfe,  0x36,  0x1c,  0xfe,  0xb1,  0x10,  0x8b,  0x59,  0x39,  0x17,  0xa2,  0x01,
+  0x38,  0x12,  0xfe,  0x35,  0x00,  0x33,  0x4b,  0x12,  0x8c,  0x02,  0x4b,  0xfe,  0x74,  0x18,  0x1a,  0xfe,
+  0x00,  0xf8,  0x1b,  0x77,  0x51,  0x1e,  0x01,  0xfe,  0x42,  0x0d,  0xd2,  0x08,  0x1c,  0x07,  0x3f,  0x01,
+  0x6a,  0x22,  0x2d,  0x3c,  0x51,  0x18,  0x02,  0x77,  0xfe,  0x98,  0x80,  0xd8,  0x0c,  0x27,  0xfe,  0x14,
+  0x0a,  0x0b,  0x09,  0x6f,  0xfe,  0x82,  0x12,  0x0b,  0x09,  0x19,  0xfe,  0x66,  0x13,  0x22,  0x60,  0x68,
+  0xc6,  0xfe,  0x83,  0x80,  0xfe,  0xc8,  0x44,  0xfe,  0x2e,  0x13,  0xfe,  0x04,  0x91,  0xfe,  0x86,  0x91,
+  0x62,  0x2d,  0xfe,  0x40,  0x59,  0xfe,  0xc1,  0x59,  0x73,  0xfb,  0x04,  0x5c,  0x2e,  0x5d,  0x0f,  0xaa,
+  0x13,  0x8c,  0x9b,  0x5c,  0x9c,  0x5d,  0x01,  0xb7,  0xab,  0x62,  0x2d,  0x16,  0x60,  0xa0,  0x3e,  0x67,
+  0x57,  0x63,  0x5e,  0x30,  0x5f,  0xe7,  0xfe,  0xe5,  0x55,  0xfe,  0x04,  0xfa,  0x3e,  0xfe,  0x05,  0xfa,
+  0x57,  0x01,  0xf6,  0xfe,  0x36,  0x10,  0x29,  0x0f,  0xaa,  0x0f,  0x8c,  0x63,  0x5e,  0x30,  0x5f,  0xa7,
+  0x0b,  0x09,  0x19,  0x1b,  0xfb,  0x63,  0x41,  0x30,  0x42,  0x0b,  0x09,  0xfe,  0xf7,  0x00,  0x37,  0x04,
+  0x5a,  0x2e,  0x5b,  0xfe,  0x10,  0x58,  0xfe,  0x91,  0x58,  0xfe,  0x14,  0x59,  0xfe,  0x95,  0x59,  0x02,
+  0x77,  0x0b,  0x09,  0x19,  0x1b,  0xfb,  0x0b,  0x09,  0xfe,  0xf7,  0x00,  0x37,  0xfe,  0x3a,  0x55,  0xfe,
+  0x19,  0x81,  0x79,  0xfe,  0x10,  0x90,  0xfe,  0x92,  0x90,  0xfe,  0xd7,  0x10,  0x3d,  0x05,  0xbf,  0x1b,
+  0xfe,  0xcc,  0x08,  0x11,  0xbf,  0xfe,  0x98,  0x80,  0xd8,  0x0c,  0xfe,  0x14,  0x13,  0x04,  0x41,  0x2e,
+  0x42,  0x73,  0xfe,  0xcc,  0x08,  0xfe,  0x0c,  0x58,  0xfe,  0x8d,  0x58,  0x02,  0x77,  0x29,  0x4e,  0xfe,
+  0x19,  0x80,  0xfe,  0xf1,  0x10,  0x0b,  0x09,  0x0c,  0xa3,  0xfe,  0x6c,  0x19,  0xfe,  0x19,  0x41,  0xfe,
+  0x94,  0x10,  0xfe,  0x6c,  0x19,  0x9b,  0x41,  0xfe,  0xed,  0x19,  0x9c,  0x42,  0xfe,  0x0c,  0x51,  0xfe,
+  0x8e,  0x51,  0xfe,  0x6b,  0x18,  0x1a,  0xfe,  0x00,  0xff,  0x2f,  0xfe,  0x7a,  0x10,  0xc3,  0xfe,  0xd2,
+  0xf0,  0xfe,  0xac,  0x0a,  0xfe,  0x76,  0x18,  0x1a,  0x18,  0xce,  0x04,  0xe1,  0x1a,  0x06,  0x83,  0x12,
+  0xfe,  0x16,  0x00,  0x02,  0x4b,  0xfe,  0xd1,  0xf0,  0xfe,  0xe2,  0x0a,  0x17,  0xa1,  0x01,  0x38,  0x12,
+  0xd6,  0xfe,  0x48,  0x10,  0xfe,  0xce,  0xf0,  0xfe,  0xca,  0x0a,  0x12,  0xfe,  0x21,  0x00,  0x02,  0x4b,
+  0xfe,  0xcd,  0xf0,  0xfe,  0xd6,  0x0a,  0x12,  0xfe,  0x22,  0x00,  0x02,  0x4b,  0xfe,  0xcb,  0xf0,  0xfe,
+  0xe2,  0x0a,  0x12,  0xfe,  0x24,  0x00,  0x02,  0x4b,  0xfe,  0xd0,  0xf0,  0xfe,  0xec,  0x0a,  0x12,  0x88,
+  0xd9,  0xfe,  0xcf,  0xf0,  0xfe,  0xf6,  0x0a,  0x12,  0x89,  0xd4,  0xfe,  0xcc,  0xf0,  0xc9,  0xfe,  0x84,
+  0x80,  0xd8,  0x19,  0xfe,  0xd5,  0x12,  0x12,  0xfe,  0x12,  0x00,  0x2c,  0xc9,  0x1f,  0x31,  0xa5,  0x25,
+  0xa6,  0x25,  0x35,  0xf3,  0x2c,  0xfe,  0x1a,  0x0b,  0x1f,  0x31,  0x80,  0xfe,  0x36,  0x0b,  0x69,  0x8e,
+  0xa5,  0xfe,  0xf0,  0x07,  0xa6,  0xfe,  0xf0,  0x07,  0x02,  0x25,  0x01,  0x4a,  0xfe,  0xdb,  0x10,  0x11,
+  0xfe,  0xe8,  0x00,  0x8b,  0x81,  0x6d,  0xfe,  0x89,  0xf0,  0x25,  0x23,  0x28,  0xfe,  0xe9,  0x09,  0x01,
+  0x0a,  0x81,  0x6d,  0x20,  0x25,  0x23,  0x28,  0x93,  0x33,  0xfe,  0x6e,  0x0b,  0x1f,  0x31,  0x02,  0xfe,
+  0x62,  0x0b,  0xc2,  0x48,  0x12,  0xfe,  0x42,  0x00,  0x02,  0x4b,  0x9f,  0x06,  0xfe,  0x81,  0x49,  0xfe,
+  0xcc,  0x12,  0x0b,  0x09,  0x0c,  0xfe,  0x5a,  0x13,  0x12,  0x00,  0x58,  0x0c,  0xfe,  0x6a,  0x12,  0x58,
+  0xfe,  0x28,  0x00,  0x27,  0xfe,  0xb4,  0x0c,  0x0e,  0x7c,  0x01,  0x14,  0x05,  0x00,  0x83,  0x34,  0xfe,
+  0x28,  0x00,  0x02,  0xfe,  0xb4,  0x0c,  0x01,  0x95,  0x01,  0x98,  0x0e,  0xbd,  0x01,  0xfe,  0x10,  0x0e,
+  0xaf,  0x08,  0x3b,  0x07,  0x99,  0x01,  0x40,  0x11,  0x43,  0x08,  0x1c,  0x07,  0x3f,  0x01,  0x76,  0x02,
+  0x26,  0x12,  0xfe,  0x44,  0x00,  0x58,  0x0c,  0xa3,  0x34,  0x0c,  0xfe,  0xc0,  0x10,  0x01,  0xb6,  0x34,
+  0x0c,  0xfe,  0xb6,  0x10,  0x01,  0xb6,  0xfe,  0x19,  0x82,  0xfe,  0x34,  0x46,  0xfe,  0x0a,  0x13,  0x34,
+  0x0c,  0x12,  0xfe,  0x43,  0x00,  0xfe,  0xa2,  0x10,  0x0b,  0x49,  0x0c,  0x37,  0x01,  0x95,  0x01,  0x98,
+  0xaf,  0x08,  0x3b,  0x07,  0x99,  0x01,  0x40,  0x11,  0x43,  0x08,  0x1c,  0x07,  0x3f,  0x01,  0x76,  0x51,
+  0x0c,  0xaf,  0x1d,  0xca,  0x02,  0xfe,  0x48,  0x03,  0x0b,  0x09,  0x0c,  0xce,  0x34,  0x0c,  0x12,  0x00,
+  0xfe,  0x54,  0x10,  0x66,  0x09,  0x1e,  0xfe,  0x50,  0x12,  0x0b,  0x09,  0x1e,  0xfe,  0x48,  0x13,  0xfe,
+  0x1c,  0x1c,  0xfe,  0x9d,  0xf0,  0xfe,  0x72,  0x0c,  0xfe,  0x1c,  0x1c,  0xfe,  0x9d,  0xf0,  0xfe,  0x78,
+  0x0c,  0x0b,  0x49,  0x1e,  0x37,  0xfe,  0x95,  0x10,  0x12,  0xfe,  0x15,  0x00,  0xfe,  0x04,  0xe6,  0x0c,
+  0x79,  0xfe,  0x26,  0x10,  0x12,  0xfe,  0x13,  0x00,  0xd4,  0x12,  0xfe,  0x47,  0x00,  0xa4,  0x12,  0xfe,
+  0x41,  0x00,  0x9d,  0x12,  0xfe,  0x24,  0x00,  0x04,  0x7b,  0x2a,  0x27,  0xeb,  0x79,  0xfe,  0x04,  0xe6,
+  0x1e,  0xfe,  0x9d,  0x41,  0xfe,  0x1c,  0x42,  0xaf,  0x01,  0xd7,  0x02,  0x26,  0xd5,  0x17,  0x0c,  0x47,
+  0xf2,  0xdf,  0x17,  0xfe,  0x31,  0x00,  0x47,  0xba,  0x01,  0xfe,  0x1c,  0x0f,  0x02,  0xfc,  0x1d,  0xfe,
+  0x06,  0xec,  0xf7,  0x85,  0x34,  0x36,  0xbc,  0x2f,  0x1d,  0xfe,  0x06,  0xea,  0xf7,  0xfe,  0x47,  0x4b,
+  0x7a,  0xfe,  0x75,  0x57,  0x04,  0x55,  0xfe,  0x98,  0x56,  0xfe,  0x28,  0x12,  0x0e,  0x7c,  0xfe,  0xfa,
+  0x14,  0x4e,  0xe5,  0x0e,  0xbd,  0xfe,  0xf0,  0x14,  0xfe,  0x49,  0x54,  0x91,  0xfe,  0x28,  0x0d,  0x0e,
+  0x1c,  0xfe,  0xe4,  0x14,  0xfe,  0x44,  0x48,  0x02,  0xfe,  0x48,  0x03,  0x0e,  0x55,  0xfe,  0xc8,  0x14,
+  0x85,  0x34,  0x36,  0xbc,  0x2f,  0x1d,  0xfe,  0xce,  0x47,  0xfe,  0xbd,  0x13,  0x02,  0x26,  0x22,  0x2b,
+  0x05,  0x10,  0xfe,  0x78,  0x12,  0x29,  0x16,  0x54,  0x16,  0xa9,  0x22,  0x43,  0x4e,  0x47,  0x43,  0xc2,
+  0xfe,  0x0c,  0x13,  0xfe,  0xbc,  0xf0,  0xfe,  0xc4,  0x0d,  0x08,  0x06,  0x16,  0x54,  0x01,  0xfe,  0xd0,
+  0x15,  0x04,  0xfe,  0x38,  0x01,  0x2e,  0xfe,  0x3a,  0x01,  0x73,  0xfe,  0xc8,  0x0d,  0x04,  0xfe,  0x38,
+  0x01,  0x1a,  0xfe,  0xf0,  0xff,  0x0f,  0xfe,  0x60,  0x01,  0x04,  0xfe,  0x3a,  0x01,  0x0f,  0xfe,  0x62,
+  0x01,  0x21,  0x06,  0x16,  0x43,  0xfe,  0x04,  0xec,  0x2b,  0x08,  0x2b,  0x07,  0x3a,  0x1d,  0x01,  0x40,
+  0x7f,  0xfe,  0x05,  0xf6,  0xfe,  0x34,  0x01,  0x01,  0xfe,  0x40,  0x16,  0x11,  0x43,  0xca,  0x08,  0x06,
+  0x03,  0x29,  0x03,  0x22,  0x54,  0xfe,  0xf7,  0x12,  0x22,  0xa9,  0x68,  0x16,  0xa9,  0x05,  0xa1,  0xfe,
+  0x93,  0x13,  0xfe,  0x24,  0x1c,  0x17,  0x18,  0x47,  0xf2,  0xdf,  0xfe,  0xd9,  0x10,  0x94,  0xfe,  0x03,
+  0xdc,  0xfe,  0x73,  0x57,  0xfe,  0x80,  0x5d,  0x03,  0x94,  0xfe,  0x03,  0xdc,  0x29,  0xfe,  0x70,  0x57,
+  0xfe,  0x33,  0x54,  0xfe,  0x3b,  0x54,  0xfe,  0x80,  0x5d,  0x03,  0xfe,  0x03,  0x57,  0x94,  0x29,  0xfe,
+  0x00,  0xcc,  0x03,  0xfe,  0x03,  0x57,  0x94,  0x7d,  0x03,  0x01,  0xfe,  0x70,  0x16,  0x3d,  0x05,  0x43,
+  0xfe,  0x0a,  0x13,  0x08,  0x1c,  0x07,  0x3f,  0xd4,  0x01,  0x95,  0x01,  0x98,  0x08,  0x3b,  0x07,  0x99,
+  0x01,  0x40,  0x11,  0xfe,  0xe9,  0x00,  0x0b,  0x09,  0x89,  0xfe,  0x52,  0x13,  0x01,  0xfe,  0x02,  0x16,
+  0xfe,  0x1e,  0x1c,  0xfe,  0x14,  0x90,  0x0f,  0xfe,  0x64,  0x01,  0xfe,  0x16,  0x90,  0x0f,  0xfe,  0x66,
+  0x01,  0x0b,  0x09,  0x74,  0x8d,  0xfe,  0x03,  0x80,  0x6b,  0x3c,  0x11,  0x75,  0x08,  0x2b,  0x07,  0x3a,
+  0x1d,  0x92,  0x01,  0x6a,  0xfe,  0x62,  0x08,  0x68,  0x3c,  0x11,  0x75,  0x08,  0x2b,  0x07,  0x3a,  0x1d,
+  0x92,  0x01,  0x6a,  0x62,  0x2d,  0x11,  0x75,  0x08,  0x2b,  0x07,  0x3a,  0x1d,  0x92,  0x01,  0x76,  0x03,
+  0xfe,  0x08,  0x1c,  0x04,  0xfe,  0xac,  0x00,  0xfe,  0x06,  0x58,  0x04,  0xfe,  0xae,  0x00,  0xfe,  0x07,
+  0x58,  0x04,  0xfe,  0xb0,  0x00,  0xfe,  0x08,  0x58,  0x04,  0xfe,  0xb2,  0x00,  0xfe,  0x09,  0x58,  0xfe,
+  0x0a,  0x1c,  0x21,  0x87,  0x16,  0xf7,  0x29,  0x0f,  0x52,  0x0f,  0x4d,  0x21,  0x10,  0x16,  0x2b,  0x16,
+  0x3a,  0x56,  0x9f,  0xd6,  0x08,  0x2b,  0x07,  0x3a,  0x1d,  0x01,  0x76,  0x7f,  0x11,  0x75,  0xfe,  0x14,
+  0x56,  0xfe,  0xd6,  0xf0,  0xfe,  0xf6,  0x0e,  0xd5,  0x8b,  0xfe,  0x14,  0x1c,  0xfe,  0x10,  0x1c,  0xfe,
+  0x18,  0x1c,  0x03,  0x1d,  0xfe,  0x0c,  0x14,  0x85,  0xfe,  0x07,  0xe6,  0x36,  0xfe,  0xce,  0x47,  0xfe,
+  0xf5,  0x13,  0x03,  0x01,  0xb6,  0x0e,  0x3b,  0x01,  0x14,  0x05,  0x10,  0xd3,  0x0e,  0x1c,  0x01,  0x14,
+  0x05,  0x10,  0xdb,  0xfe,  0x44,  0x58,  0x3c,  0xfe,  0x01,  0xec,  0xba,  0xfe,  0x9e,  0x40,  0xfe,  0x9d,
+  0xe7,  0x00,  0xfe,  0x9c,  0xe7,  0x1e,  0x9e,  0x2d,  0x01,  0xd7,  0xfe,  0xc9,  0x10,  0x03,  0x35,  0x81,
+  0x6d,  0x23,  0x28,  0xb1,  0x05,  0x1e,  0xfe,  0x48,  0x12,  0x05,  0x0c,  0xfe,  0x4c,  0x12,  0x05,  0x18,
+  0x38,  0x05,  0xcc,  0x1b,  0xfe,  0xc0,  0x10,  0x05,  0xfe,  0x23,  0x00,  0x1b,  0xfe,  0xcc,  0x10,  0x05,
+  0x06,  0x1b,  0xfe,  0x2a,  0x11,  0x05,  0x19,  0xfe,  0x12,  0x12,  0x05,  0x00,  0x1b,  0x25,  0x17,  0xcc,
+  0x01,  0x38,  0xc4,  0x39,  0x01,  0x0a,  0x80,  0x4a,  0x03,  0x39,  0x11,  0xfe,  0xcc,  0x00,  0x02,  0x26,
+  0x39,  0x3d,  0x05,  0xbf,  0xfe,  0xe3,  0x13,  0x63,  0x41,  0x30,  0x42,  0x73,  0xfe,  0x7e,  0x10,  0x0b,
+  0x09,  0x6f,  0xfe,  0x72,  0x12,  0xa0,  0x3e,  0x67,  0x57,  0xe7,  0xfe,  0xe5,  0x55,  0x91,  0xfe,  0x48,
+  0x10,  0x22,  0x60,  0xfe,  0x26,  0x13,  0x04,  0xaa,  0x2e,  0x8c,  0x73,  0xfe,  0x98,  0x0c,  0x0f,  0x5c,
+  0x13,  0x5d,  0x29,  0x0f,  0xaa,  0x0f,  0x8c,  0x01,  0xb7,  0x21,  0x87,  0x6b,  0x16,  0x60,  0x01,  0xf6,
+  0xa0,  0x3e,  0x67,  0x57,  0xfe,  0x04,  0x55,  0xfe,  0xa5,  0x55,  0xfe,  0x04,  0xfa,  0x3e,  0xfe,  0x05,
+  0xfa,  0x57,  0xfe,  0x91,  0x10,  0x04,  0x5e,  0x2e,  0x5f,  0xfe,  0x40,  0x56,  0xfe,  0xe1,  0x56,  0x0f,
+  0x5e,  0x13,  0x5f,  0xd1,  0xa0,  0x3e,  0x67,  0x57,  0xe7,  0xfe,  0xe5,  0x55,  0x04,  0x5a,  0x2e,  0x5b,
+  0xfe,  0x00,  0x56,  0xfe,  0xa1,  0x56,  0x0f,  0x5a,  0x13,  0x5b,  0x0b,  0x09,  0x6f,  0xfe,  0x1e,  0x12,
+  0x22,  0x60,  0xfe,  0x1f,  0x40,  0x04,  0x5c,  0x2e,  0x5d,  0xfe,  0x2c,  0x50,  0xfe,  0xae,  0x50,  0x04,
+  0x5e,  0x2e,  0x5f,  0xfe,  0x34,  0x50,  0xfe,  0xb6,  0x50,  0x04,  0x5a,  0x2e,  0x5b,  0xfe,  0x08,  0x50,
+  0xfe,  0x8a,  0x50,  0x04,  0x41,  0x2e,  0x42,  0xfe,  0x28,  0x50,  0xfe,  0xaa,  0x50,  0x02,  0x97,  0x21,
+  0x06,  0x16,  0xf1,  0x02,  0x78,  0x39,  0x01,  0x0a,  0x20,  0x4c,  0x23,  0x28,  0xb1,  0x05,  0x06,  0x27,
+  0x4c,  0x3d,  0x05,  0xbf,  0x27,  0x78,  0x01,  0xee,  0x1a,  0x4f,  0x1b,  0x4c,  0x0b,  0x09,  0x0c,  0xde,
+  0x63,  0x41,  0x30,  0x42,  0xfe,  0x0a,  0x55,  0x2f,  0xfe,  0x8b,  0x55,  0x9b,  0x41,  0x9c,  0x42,  0xfe,
+  0x0c,  0x51,  0xfe,  0x8e,  0x51,  0x02,  0x78,  0xfe,  0x19,  0x81,  0xfe,  0x0a,  0x45,  0xfe,  0x19,  0x41,
+  0x02,  0x78,  0x39,  0x01,  0x0a,  0x20,  0xfe,  0xc2,  0x0f,  0x23,  0x28,  0xfe,  0xe9,  0x09,  0x58,  0x18,
+  0xfe,  0x94,  0x12,  0x58,  0x0c,  0x50,  0x02,  0x4c,  0x2c,  0xfe,  0x4a,  0x11,  0x1f,  0x31,  0x20,  0xfe,
+  0xc2,  0x0f,  0x23,  0x28,  0x93,  0x05,  0x18,  0x27,  0x4c,  0x01,  0x0a,  0x20,  0xfe,  0xc2,  0x0f,  0x23,
+  0x28,  0xfe,  0xe8,  0x09,  0x56,  0x04,  0xfe,  0x9c,  0x00,  0x2a,  0x2f,  0xfe,  0xbb,  0x45,  0x58,  0x00,
+  0x48,  0x34,  0x06,  0x9f,  0x4f,  0xfe,  0xc0,  0x14,  0xfe,  0xf8,  0x14,  0xa8,  0x3d,  0x05,  0xbe,  0xfe,
+  0x16,  0x13,  0x04,  0xf4,  0x2a,  0xce,  0x04,  0x4d,  0x2a,  0x2f,  0x59,  0x02,  0x78,  0xfe,  0xc0,  0x5d,
+  0xfe,  0xe4,  0x14,  0xfe,  0x03,  0x17,  0x04,  0x52,  0xb9,  0x0f,  0x52,  0x59,  0x39,  0x01,  0x0a,  0x24,
+  0x97,  0x01,  0xfe,  0xf0,  0x13,  0x02,  0x97,  0x2c,  0xfe,  0xd4,  0x11,  0x1f,  0x31,  0x20,  0x4c,  0x23,
+  0x28,  0x93,  0x05,  0x06,  0x27,  0x4c,  0xfe,  0xf6,  0x14,  0xfe,  0x42,  0x58,  0xfe,  0x70,  0x14,  0xfe,
+  0x92,  0x14,  0xa8,  0xfe,  0x4a,  0xf4,  0x0c,  0x1b,  0x4c,  0xfe,  0x4a,  0xf4,  0x06,  0xd2,  0x3d,  0x05,
+  0xbe,  0xc7,  0x02,  0x78,  0x04,  0x4d,  0xb9,  0x0f,  0x4d,  0x59,  0x39,  0x01,  0x0a,  0x24,  0x97,  0x01,
+  0xfe,  0x1e,  0x14,  0x02,  0x97,  0x24,  0xfe,  0x3c,  0x12,  0x71,  0xef,  0x71,  0x03,  0x33,  0x8d,  0x69,
+  0x8d,  0x59,  0x39,  0x01,  0x0a,  0xfe,  0xe3,  0x10,  0x08,  0x61,  0xff,  0x02,  0x00,  0x57,  0x64,  0x7e,
+  0x1a,  0xfe,  0xff,  0x7f,  0xfe,  0x30,  0x56,  0xfe,  0x00,  0x5c,  0x03,  0x08,  0x61,  0xff,  0x02,  0x00,
+  0x57,  0x64,  0x7e,  0x1a,  0x4f,  0xfe,  0x30,  0x56,  0xfe,  0x00,  0x5c,  0x03,  0x08,  0x61,  0xff,  0x02,
+  0x00,  0x57,  0x64,  0x7e,  0x03,  0x08,  0x61,  0xff,  0x02,  0x00,  0x57,  0x64,  0x7e,  0xfe,  0x0b,  0x58,
+  0x03,  0x0e,  0x52,  0x01,  0x9a,  0x0e,  0x4d,  0x01,  0x9a,  0x03,  0xc6,  0x1a,  0x10,  0xff,  0x03,  0x00,
+  0x54,  0xfe,  0x00,  0xf4,  0x19,  0x64,  0xfe,  0x00,  0x7d,  0xfe,  0x01,  0x7d,  0xfe,  0x02,  0x7d,  0xfe,
+  0x03,  0x7c,  0x62,  0x2d,  0x0f,  0x5a,  0x13,  0x5b,  0x9b,  0x5e,  0x9c,  0x5f,  0x03,  0xfe,  0x62,  0x18,
+  0xfe,  0x82,  0x5a,  0xfe,  0xe1,  0x1a,  0xb4,  0xfe,  0x02,  0x58,  0x03,  0x01,  0xfe,  0x60,  0x18,  0xfe,
+  0x42,  0x48,  0x79,  0x56,  0x7a,  0x01,  0x0a,  0x20,  0xfe,  0xe8,  0x13,  0x23,  0x28,  0xfe,  0xe9,  0x09,
+  0xfe,  0xc1,  0x59,  0x01,  0x0a,  0x20,  0xfe,  0xe8,  0x13,  0x23,  0x28,  0xfe,  0xe8,  0x0a,  0x04,  0xf4,
+  0x2a,  0xfe,  0xc2,  0x12,  0x29,  0xad,  0x1e,  0xde,  0x58,  0xcd,  0x72,  0xfe,  0x38,  0x13,  0x50,  0x08,
+  0x06,  0x07,  0xcd,  0x9f,  0xfe,  0x00,  0x10,  0xfe,  0x78,  0x10,  0xff,  0x02,  0x83,  0x55,  0xa4,  0xff,
+  0x02,  0x83,  0x55,  0xad,  0x18,  0xfe,  0x12,  0x13,  0x70,  0xfe,  0x30,  0x00,  0x91,  0xf0,  0x07,  0x84,
+  0x08,  0x06,  0xfe,  0x56,  0x10,  0xad,  0x0c,  0xfe,  0x16,  0x13,  0x70,  0xfe,  0x64,  0x00,  0x91,  0xf0,
+  0x0e,  0xfe,  0x64,  0x00,  0x07,  0x88,  0x08,  0x06,  0xfe,  0x28,  0x10,  0xad,  0x06,  0xfe,  0x5e,  0x13,
+  0x70,  0xfe,  0xc8,  0x00,  0x91,  0xf0,  0x0e,  0xfe,  0xc8,  0x00,  0x07,  0x54,  0x08,  0x06,  0xd1,  0x70,
+  0xfe,  0x90,  0x01,  0xea,  0xfe,  0x9e,  0x13,  0x7a,  0xa7,  0xfe,  0x43,  0xf4,  0xa9,  0xfe,  0x56,  0xf0,
+  0xfe,  0xb0,  0x13,  0xfe,  0x04,  0xf4,  0x61,  0xfe,  0x43,  0xf4,  0x88,  0xfe,  0xf3,  0x10,  0xac,  0x01,
+  0xfe,  0x7a,  0x12,  0x1a,  0x4f,  0xd3,  0xfe,  0x00,  0x17,  0xfe,  0x4d,  0xe4,  0x87,  0xea,  0xfe,  0xe2,
+  0x13,  0x7a,  0xfe,  0x14,  0x10,  0xfe,  0x00,  0x17,  0xfe,  0x4d,  0xe4,  0x19,  0xea,  0xfe,  0xe2,  0x13,
+  0xc8,  0x19,  0x9d,  0x56,  0x7a,  0x08,  0x06,  0xfe,  0xb4,  0x56,  0xfe,  0xc3,  0x58,  0x03,  0x56,  0x08,
+  0x0c,  0x03,  0x15,  0x06,  0x01,  0x0a,  0x24,  0xdc,  0x15,  0x0c,  0x01,  0x0a,  0x24,  0xdc,  0x15,  0x18,
+  0x01,  0x0a,  0x24,  0xdc,  0x71,  0xfe,  0x89,  0x49,  0x01,  0x0a,  0x03,  0x15,  0x06,  0x01,  0x0a,  0x24,
+  0x90,  0x15,  0x18,  0x01,  0x0a,  0x24,  0x90,  0x15,  0x06,  0x01,  0x0a,  0x24,  0x90,  0xfe,  0x89,  0x49,
+  0x01,  0x0a,  0x24,  0x90,  0x71,  0xfe,  0x89,  0x4a,  0x01,  0x0a,  0x03,  0x56,  0x03,  0x22,  0xe2,  0x05,
+  0x06,  0xfe,  0x44,  0x13,  0xab,  0x16,  0xe2,  0xfe,  0x49,  0xf4,  0x00,  0x50,  0x71,  0xc4,  0x59,  0xfe,
+  0x01,  0xec,  0xfe,  0x27,  0x01,  0xef,  0x01,  0x0a,  0x3d,  0x05,  0xfe,  0xe3,  0x00,  0xfe,  0x20,  0x13,
+  0x20,  0xfe,  0xa0,  0x14,  0x29,  0x16,  0xf1,  0x01,  0x4a,  0x22,  0xf1,  0x05,  0x06,  0x48,  0x0b,  0x49,
+  0x06,  0x37,  0x03,  0x0f,  0x53,  0x13,  0x8a,  0xfe,  0x43,  0x58,  0x01,  0x14,  0x05,  0x10,  0xfe,  0x1e,
+  0x12,  0x45,  0xe6,  0x8f,  0x01,  0x44,  0xfe,  0x90,  0x4d,  0xe0,  0x10,  0xfe,  0xc5,  0x59,  0x01,  0x44,
+  0xfe,  0x8d,  0x56,  0xb4,  0x45,  0x03,  0x45,  0x30,  0x8a,  0x01,  0x14,  0x45,  0x8f,  0x01,  0x44,  0xe4,
+  0x10,  0xe0,  0x10,  0x30,  0x53,  0x70,  0x1c,  0x83,  0x0e,  0x55,  0x01,  0xc0,  0x03,  0x0f,  0x53,  0x13,
+  0x8a,  0xfe,  0xc3,  0x58,  0x01,  0x14,  0x05,  0x10,  0xfe,  0x1a,  0x12,  0x45,  0xe6,  0x8f,  0x01,  0x44,
+  0xe4,  0x10,  0xfe,  0x80,  0x4d,  0xfe,  0xc5,  0x59,  0x01,  0x44,  0x45,  0x03,  0x45,  0x30,  0x53,  0x01,
+  0x14,  0x45,  0x8f,  0x01,  0x44,  0xe4,  0x10,  0xe0,  0x10,  0x30,  0x53,  0x70,  0x1c,  0x83,  0x0e,  0x55,
+  0x01,  0xc0,  0x03,  0x0f,  0x53,  0x13,  0x8a,  0xfe,  0x43,  0x58,  0x01,  0x14,  0xfe,  0x42,  0x48,  0x8f,
+  0x01,  0x44,  0xfe,  0xc0,  0x5a,  0xac,  0xfe,  0x00,  0xcd,  0xfe,  0x01,  0xcc,  0xfe,  0x4a,  0x46,  0xde,
+  0x94,  0x7d,  0x05,  0x10,  0xfe,  0x2e,  0x13,  0x67,  0x53,  0xfe,  0x4d,  0xf4,  0x1c,  0xfe,  0x1c,  0x13,
+  0x0e,  0x55,  0x01,  0x9a,  0xa7,  0xfe,  0x40,  0x4c,  0xfe,  0xc5,  0x58,  0x01,  0x44,  0xfe,  0x00,  0x07,
+  0x7d,  0x05,  0x10,  0x83,  0x67,  0x8a,  0xfe,  0x05,  0x57,  0xfe,  0x08,  0x10,  0xfe,  0x45,  0x58,  0x01,
+  0x44,  0xfe,  0x8d,  0x56,  0xb4,  0xfe,  0x80,  0x4c,  0xfe,  0x05,  0x17,  0x03,  0x07,  0x10,  0x6e,  0x65,
+  0xfe,  0x60,  0x01,  0xfe,  0x18,  0xdf,  0xfe,  0x19,  0xde,  0xfe,  0x24,  0x1c,  0xdd,  0x36,  0x96,  0xfe,
+  0xe4,  0x15,  0x01,  0xfe,  0xea,  0x16,  0xfe,  0x0c,  0x13,  0x86,  0x36,  0x65,  0xfe,  0x2c,  0x01,  0xfe,
+  0x2f,  0x19,  0x03,  0xb5,  0x27,  0xfe,  0xd4,  0x15,  0xfe,  0xda,  0x10,  0x07,  0x10,  0x6e,  0x04,  0xfe,
+  0x64,  0x01,  0xfe,  0x00,  0xf4,  0x19,  0xfe,  0x18,  0x58,  0x04,  0xfe,  0x66,  0x01,  0xfe,  0x19,  0x58,
+  0x86,  0x19,  0xfe,  0x3c,  0x90,  0xfe,  0x30,  0xf4,  0x06,  0xfe,  0x3c,  0x50,  0x65,  0xfe,  0x38,  0x00,
+  0xfe,  0x0f,  0x79,  0xfe,  0x1c,  0xf7,  0x19,  0x96,  0xfe,  0x2e,  0x16,  0xfe,  0xb6,  0x14,  0x2f,  0x03,
+  0xb5,  0x27,  0xfe,  0x06,  0x16,  0xfe,  0x9c,  0x10,  0x07,  0x10,  0x6e,  0xb4,  0xfe,  0x18,  0xdf,  0xfe,
+  0x19,  0xdf,  0xdd,  0x3e,  0x96,  0xfe,  0x50,  0x16,  0xfe,  0x94,  0x14,  0xfe,  0x10,  0x13,  0x86,  0x3e,
+  0x65,  0x1e,  0xfe,  0xaf,  0x19,  0xfe,  0x98,  0xe7,  0x00,  0x03,  0xb5,  0x27,  0xfe,  0x44,  0x16,  0xfe,
+  0x6c,  0x10,  0x07,  0x10,  0x6e,  0xfe,  0x30,  0xbc,  0xfe,  0xb2,  0xbc,  0x86,  0xda,  0x65,  0x1e,  0xfe,
+  0x0f,  0x79,  0xfe,  0x1c,  0xf7,  0xda,  0x96,  0xfe,  0x88,  0x16,  0xfe,  0x5c,  0x14,  0x2f,  0x03,  0xb5,
+  0x27,  0xfe,  0x74,  0x16,  0xfe,  0x42,  0x10,  0xfe,  0x02,  0xf6,  0x10,  0x6e,  0xfe,  0x18,  0xfe,  0x5c,
+  0xfe,  0x19,  0xfe,  0x5d,  0xc6,  0xdd,  0x74,  0x96,  0xfe,  0xae,  0x16,  0xfe,  0x36,  0x14,  0xfe,  0x1c,
+  0x13,  0x86,  0x74,  0x4e,  0xfe,  0x83,  0x58,  0xfe,  0xaf,  0x19,  0xfe,  0x80,  0xe7,  0x10,  0xfe,  0x81,
+  0xe7,  0x10,  0x11,  0xfe,  0xdd,  0x00,  0x62,  0x2d,  0x03,  0x62,  0x2d,  0xfe,  0x12,  0x45,  0x27,  0xfe,
+  0x9e,  0x16,  0x17,  0x06,  0x47,  0xf2,  0xdf,  0x02,  0x26,  0xfe,  0x39,  0xf0,  0xfe,  0xf2,  0x16,  0x29,
+  0x03,  0xfe,  0x7e,  0x18,  0x1a,  0x18,  0x82,  0x08,  0x0d,  0x03,  0x6e,  0x04,  0xe1,  0x1a,  0x06,  0xfe,
+  0xef,  0x12,  0xfe,  0xe1,  0x10,  0x1d,  0x0e,  0x1c,  0x01,  0x14,  0x05,  0x10,  0x48,  0x3c,  0xfe,  0x78,
+  0x14,  0xfe,  0x34,  0x12,  0x4f,  0x85,  0x34,  0x36,  0xbc,  0xfe,  0xe9,  0x13,  0x1d,  0x0e,  0x3b,  0x01,
+  0x14,  0x05,  0x10,  0x48,  0x3c,  0x90,  0xe3,  0x4f,  0x85,  0x34,  0x36,  0xbc,  0xfe,  0xe9,  0x13,  0x07,
+  0x0c,  0x03,  0xfe,  0x9c,  0xe7,  0x0c,  0x12,  0xfe,  0x15,  0x00,  0x92,  0x9e,  0x2d,  0x01,  0xd7,  0x07,
+  0x06,  0x03,  0x0b,  0x49,  0x36,  0x37,  0x08,  0x3b,  0x07,  0x99,  0x01,  0x40,  0x11,  0x43,  0x08,  0x1c,
+  0x07,  0x3f,  0x01,  0x76,  0x07,  0x06,  0x03,  0xfe,  0x38,  0x90,  0xfe,  0xba,  0x90,  0x63,  0xf5,  0x30,
+  0x75,  0xfe,  0x48,  0x55,  0x2f,  0xfe,  0xc9,  0x55,  0x03,  0x22,  0xbb,  0x6b,  0x16,  0xbb,  0x03,  0x0e,
+  0xbd,  0x01,  0x14,  0xe5,  0x0e,  0x7c,  0x01,  0x14,  0xfe,  0x49,  0x44,  0x27,  0xfe,  0xe8,  0x17,  0x0e,
+  0x1c,  0x01,  0x14,  0x05,  0x10,  0x48,  0x0e,  0x55,  0x01,  0xc0,  0x0e,  0x7c,  0x01,  0x14,  0x6b,  0x7d,
+  0x03,  0xfe,  0x40,  0x5e,  0xfe,  0xe2,  0x08,  0xfe,  0xc0,  0x4c,  0x22,  0x3a,  0x05,  0x10,  0xfe,  0x52,
+  0x12,  0x3c,  0x05,  0x00,  0xfe,  0x18,  0x12,  0xfe,  0xe1,  0x18,  0xfe,  0x19,  0xf4,  0xfe,  0x7f,  0x00,
+  0xfe,  0x10,  0x13,  0xfe,  0xe2,  0x08,  0x6b,  0x3c,  0x3d,  0x05,  0x75,  0xa3,  0xfe,  0x82,  0x48,  0xfe,
+  0x01,  0x80,  0xfe,  0xd7,  0x10,  0xfe,  0xc4,  0x48,  0x08,  0x2b,  0x07,  0x3a,  0xfe,  0x40,  0x5f,  0x1d,
+  0x01,  0x40,  0x11,  0xfe,  0xdd,  0x00,  0xfe,  0x14,  0x46,  0x08,  0x2b,  0x07,  0x3a,  0x01,  0x40,  0x11,
+  0xfe,  0xdd,  0x00,  0xfe,  0x40,  0x4a,  0x68,  0xfe,  0x06,  0x17,  0xfe,  0x01,  0x07,  0xfe,  0x82,  0x48,
+  0xfe,  0x04,  0x17,  0x03,  0xe9,  0x18,  0x72,  0xfe,  0x70,  0x18,  0x04,  0xfe,  0x90,  0x00,  0xfe,  0x3a,
+  0x45,  0xfe,  0x2c,  0x10,  0xe9,  0xcc,  0x72,  0xfe,  0x82,  0x18,  0x04,  0xfe,  0x92,  0x00,  0xc5,  0x1e,
+  0xd9,  0xe9,  0xfe,  0x0b,  0x00,  0x72,  0xfe,  0x94,  0x18,  0x04,  0xfe,  0x94,  0x00,  0xc5,  0x19,  0xfe,
+  0x08,  0x10,  0x04,  0xfe,  0x96,  0x00,  0xc5,  0x84,  0xfe,  0x4e,  0x45,  0xd2,  0xfe,  0x0a,  0x45,  0xff,
+  0x04,  0x68,  0x54,  0xfe,  0xf1,  0x10,  0x1a,  0x87,  0x03,  0x05,  0xa1,  0xfe,  0x5a,  0xf0,  0xfe,  0xc0,
+  0x18,  0x21,  0xfe,  0x09,  0x00,  0xfe,  0x34,  0x10,  0x05,  0x1e,  0xfe,  0x5a,  0xf0,  0xfe,  0xce,  0x18,
+  0x21,  0xcd,  0xfe,  0x26,  0x10,  0x05,  0x18,  0x82,  0x21,  0x84,  0xd9,  0x05,  0x0c,  0x82,  0x21,  0x88,
+  0xfe,  0x0e,  0x10,  0x05,  0x06,  0x82,  0x21,  0x54,  0xc4,  0xab,  0x03,  0x17,  0xfe,  0x09,  0x00,  0x01,
+  0x38,  0x2c,  0xfe,  0xfe,  0x18,  0x04,  0x6d,  0xac,  0x03,  0x1f,  0xfe,  0x16,  0x19,  0xfe,  0x14,  0xf0,
+  0x0a,  0x2c,  0xfe,  0x12,  0x19,  0x03,  0xff,  0x34,  0x00,  0x00,};
+
+STATIC unsigned short _adv_asc3550_size =
+    sizeof(_adv_asc3550_buf); /* 0x13AA */
+STATIC unsigned long _adv_asc3550_chksum =
+    0x04F4788EUL; /* Expanded checksum. */
+
+STATIC unsigned char _adv_asc38C0800_buf[] = {
+  0x00,  0x00,  0x00,  0xf2,  0x00,  0xf0,  0x00,  0x16,  0x00,  0xfc,  0x48,  0xe4,  0x01,  0x00,  0x00,  0xf6,
+  0x18,  0xe4,  0x01,  0xf6,  0x18,  0x80,  0x02,  0x00,  0x02,  0x1a,  0xff,  0xff,  0x00,  0xfa,  0x03,  0xf6,
+  0xff,  0x00,  0x82,  0xe7,  0x01,  0xfa,  0x9e,  0xe7,  0x09,  0xe7,  0xe6,  0x0e,  0x00,  0xea,  0x01,  0xe6,
+  0x03,  0x00,  0x1e,  0xf0,  0x55,  0xf0,  0x18,  0xf4,  0x3e,  0x57,  0x04,  0x00,  0x3e,  0x01,  0x85,  0xf0,
+  0x00,  0xe6,  0x03,  0xfc,  0x08,  0x00,  0x32,  0xf0,  0x38,  0x54,  0x84,  0x0d,  0x86,  0xf0,  0xd4,  0x01,
+  0xd5,  0xf0,  0xee,  0x19,  0x00,  0xec,  0x01,  0xfc,  0x98,  0x57,  0xbc,  0x00,  0x10,  0x13,  0xb1,  0xf0,
+  0x02,  0x13,  0x3c,  0x00,  0x7e,  0x0d,  0xb4,  0x00,  0x00,  0x57,  0x01,  0xf0,  0x02,  0xfc,  0x03,  0xe6,
+  0x0c,  0x1c,  0x10,  0x00,  0x18,  0x40,  0x3e,  0x1c,  0xbd,  0x00,  0xe0,  0x00,  0x02,  0x80,  0x3e,  0x00,
+  0x46,  0x16,  0x4a,  0x10,  0x6c,  0x01,  0x6e,  0x01,  0x74,  0x01,  0x76,  0x01,  0xb9,  0x54,  0xba,  0x13,
+  0xbb,  0x00,  0x00,  0x4e,  0x01,  0x01,  0x01,  0xea,  0x02,  0x48,  0x02,  0xfa,  0x08,  0x12,  0x30,  0xe4,
+  0x3c,  0x56,  0x4e,  0x01,  0x5d,  0xf0,  0x7a,  0x01,  0x88,  0x0d,  0x8e,  0x10,  0xb6,  0x00,  0xc4,  0x08,
+  0x00,  0x80,  0x04,  0x12,  0x05,  0xfc,  0x24,  0x01,  0x28,  0x01,  0x32,  0x00,  0x3c,  0x01,  0x40,  0x00,
+  0x4b,  0xe4,  0x4b,  0xf4,  0x4c,  0x1c,  0x68,  0x01,  0x6a,  0x01,  0x70,  0x01,  0x72,  0x01,  0x78,  0x01,
+  0x7c,  0x01,  0xbb,  0x55,  0x00,  0x01,  0x02,  0xee,  0x03,  0x58,  0x03,  0xf7,  0x03,  0xfa,  0x04,  0x80,
+  0x08,  0x44,  0x09,  0xf0,  0x10,  0x44,  0x1b,  0x80,  0x20,  0x01,  0x38,  0x1c,  0x4e,  0x1c,  0x5b,  0xf0,
+  0x80,  0x00,  0x8a,  0x15,  0x98,  0x10,  0xaa,  0x00,  0xbd,  0x56,  0xbe,  0x00,  0xc0,  0x00,  0x00,  0x4c,
+  0x00,  0xdc,  0x02,  0x4a,  0x04,  0xfc,  0x05,  0xf0,  0x05,  0xf8,  0x06,  0x13,  0x06,  0xf7,  0x08,  0x13,
+  0x0c,  0x00,  0x0e,  0x47,  0x0e,  0xf7,  0x0f,  0x00,  0x1c,  0x0c,  0x20,  0x00,  0x2a,  0x01,  0x32,  0x1c,
+  0x36,  0x00,  0x42,  0x54,  0x44,  0x0b,  0x44,  0x55,  0x45,  0x5a,  0x59,  0xf0,  0x5c,  0xf0,  0x62,  0x0a,
+  0x69,  0x08,  0x78,  0x13,  0x83,  0x59,  0x8e,  0x18,  0x9a,  0x10,  0x9a,  0x18,  0xb8,  0xf0,  0xd6,  0x0e,
+  0xea,  0x15,  0xf0,  0x00,  0x04,  0x10,  0x04,  0xea,  0x04,  0xf6,  0x05,  0x00,  0x06,  0x00,  0x06,  0x12,
+  0x0a,  0x10,  0x0a,  0x12,  0x0b,  0xf0,  0x0c,  0x10,  0x0c,  0xf0,  0x12,  0x10,  0x19,  0x00,  0x19,  0xe4,
+  0x2a,  0x12,  0x30,  0x1c,  0x33,  0x00,  0x34,  0x00,  0x36,  0x15,  0x38,  0x44,  0x3a,  0x15,  0x40,  0x5c,
+  0x4a,  0xe4,  0x62,  0x1a,  0x68,  0x08,  0x68,  0x54,  0x7a,  0x17,  0x83,  0x55,  0x83,  0x5a,  0x91,  0x44,
+  0xa2,  0x10,  0xa4,  0x00,  0xb0,  0x57,  0xb5,  0x00,  0xba,  0x00,  0xcc,  0x0e,  0xce,  0x45,  0xd0,  0x00,
+  0xe1,  0x00,  0xe5,  0x55,  0xe7,  0x00,  0x00,  0x54,  0x01,  0x48,  0x01,  0x58,  0x02,  0x10,  0x02,  0xe6,
+  0x03,  0xa1,  0x04,  0x13,  0x05,  0xe6,  0x06,  0x83,  0x06,  0xf0,  0x07,  0x00,  0x0a,  0x00,  0x0a,  0xf0,
+  0x0c,  0x12,  0x0c,  0x13,  0x0e,  0x13,  0x10,  0x04,  0x10,  0x10,  0x12,  0x1c,  0x19,  0x81,  0x1a,  0x10,
+  0x1c,  0x00,  0x1c,  0x12,  0x1c,  0x13,  0x1d,  0xf7,  0x1e,  0x13,  0x20,  0x1c,  0x20,  0xe7,  0x22,  0x01,
+  0x26,  0x01,  0x30,  0xe7,  0x38,  0x12,  0x3a,  0x55,  0x3f,  0x00,  0x41,  0x58,  0x43,  0x48,  0x46,  0x1c,
+  0x4e,  0xe4,  0x5a,  0x13,  0x68,  0x13,  0x72,  0x14,  0x76,  0x02,  0x77,  0x57,  0x78,  0x03,  0x89,  0x48,
+  0x8a,  0x13,  0x98,  0x80,  0x99,  0x00,  0x9b,  0x00,  0x9c,  0x32,  0xfe,  0x9c,  0xf0,  0x27,  0x02,  0xfe,
+  0xa6,  0x0d,  0xff,  0x10,  0x00,  0x00,  0xfe,  0xc6,  0x01,  0xfe,  0x18,  0x1a,  0x00,  0xfe,  0xc4,  0x01,
+  0xfe,  0x84,  0x01,  0xff,  0x03,  0x00,  0x00,  0x30,  0xfe,  0x01,  0x05,  0xff,  0x40,  0x00,  0x00,  0x0d,
+  0xff,  0x09,  0x00,  0x00,  0xff,  0x08,  0x01,  0x01,  0xff,  0x10,  0xff,  0xff,  0xff,  0x1f,  0x00,  0x00,
+  0xff,  0x10,  0xff,  0xff,  0xff,  0x11,  0x00,  0x00,  0xfe,  0x78,  0x56,  0xfe,  0x34,  0x12,  0xff,  0x21,
+  0x00,  0x00,  0xfe,  0x04,  0xf7,  0xfe,  0xc4,  0x01,  0x38,  0x86,  0x0b,  0x01,  0xfe,  0x96,  0x0f,  0xfe,
+  0x04,  0xf7,  0xfe,  0xc4,  0x01,  0x86,  0x0b,  0x1c,  0x38,  0xfe,  0x3d,  0xf0,  0xfe,  0xfc,  0x01,  0xfe,
+  0x20,  0xf0,  0xdb,  0x04,  0x5e,  0x59,  0x02,  0xfe,  0xc2,  0x0d,  0x01,  0xfe,  0x22,  0x0e,  0xfe,  0xe9,
+  0x12,  0x02,  0xfe,  0x08,  0x03,  0xfe,  0x28,  0x1c,  0x04,  0xfe,  0xa6,  0x00,  0xfe,  0xdd,  0x12,  0x46,
+  0x12,  0xfe,  0xa6,  0x00,  0xcd,  0xfe,  0x48,  0xf0,  0xfe,  0x80,  0x02,  0xfe,  0x49,  0xf0,  0xfe,  0x9a,
+  0x02,  0xfe,  0x4a,  0xf0,  0xfe,  0xb8,  0x02,  0xfe,  0x46,  0xf0,  0xfe,  0x4a,  0x02,  0xfe,  0x47,  0xf0,
+  0xfe,  0x50,  0x02,  0xfe,  0x43,  0xf0,  0xfe,  0x3e,  0x02,  0xfe,  0x44,  0xf0,  0xfe,  0x42,  0x02,  0xfe,
+  0x45,  0xf0,  0xfe,  0x46,  0x02,  0x09,  0x0b,  0xa2,  0x09,  0x06,  0x12,  0xc1,  0x02,  0x27,  0xfe,  0x00,
+  0x1c,  0xfe,  0xf1,  0x10,  0xfe,  0x02,  0x1c,  0xfe,  0xed,  0x10,  0xfe,  0x1e,  0x1c,  0xfe,  0xe9,  0x10,
+  0x01,  0xfe,  0xee,  0x17,  0xfe,  0xe7,  0x10,  0xfe,  0x06,  0xfc,  0xfe,  0xa8,  0x00,  0x0f,  0x7d,  0x01,
+  0xc5,  0x02,  0x27,  0x17,  0x5d,  0x4b,  0xc3,  0x01,  0xab,  0x0f,  0x7d,  0x01,  0x9f,  0xfe,  0xbd,  0x10,
+  0x0f,  0x7d,  0x01,  0x9f,  0xfe,  0xad,  0x10,  0xfe,  0x16,  0x1c,  0xfe,  0x58,  0x1c,  0x09,  0x06,  0x12,
+  0xc1,  0x38,  0x19,  0x27,  0xfe,  0x3d,  0xf0,  0xfe,  0xfc,  0x01,  0x28,  0xfe,  0x8e,  0x02,  0xfe,  0x5a,
+  0x1c,  0xdd,  0xfe,  0x14,  0x1c,  0x17,  0xfe,  0x30,  0x00,  0x4b,  0xc3,  0x01,  0xfe,  0xfc,  0x0f,  0x09,
+  0x06,  0x12,  0xc1,  0x02,  0xfe,  0xc6,  0x01,  0x2a,  0x2d,  0x05,  0x10,  0x30,  0xfe,  0x69,  0x10,  0x09,
+  0x06,  0x12,  0xc1,  0xfe,  0x04,  0xec,  0x2d,  0x07,  0x2d,  0x09,  0x3c,  0x1c,  0x01,  0x40,  0x81,  0xfe,
+  0x05,  0xf6,  0xfe,  0xa8,  0x00,  0x01,  0xfe,  0x20,  0x17,  0x0a,  0x4f,  0x8d,  0x3a,  0x11,  0x48,  0x1c,
+  0xd3,  0x07,  0x1e,  0x09,  0x51,  0x01,  0xa0,  0x02,  0x27,  0x0f,  0x3d,  0x01,  0x15,  0x05,  0x10,  0xda,
+  0x07,  0x1e,  0x09,  0x51,  0x01,  0x79,  0xfe,  0x28,  0x10,  0x0f,  0xc7,  0x01,  0x15,  0xed,  0x0f,  0x7e,
+  0x01,  0x15,  0xfe,  0x49,  0x54,  0x77,  0xfe,  0x16,  0x03,  0x07,  0x1e,  0x09,  0x51,  0x01,  0xa0,  0x02,
+  0x27,  0x38,  0x81,  0xfe,  0x02,  0xe8,  0x33,  0xfe,  0xbf,  0x57,  0xfe,  0x9e,  0x43,  0xf5,  0xfe,  0x07,
+  0x4b,  0xfe,  0x20,  0xf0,  0xdb,  0xfe,  0x40,  0x1c,  0x19,  0xf6,  0xfe,  0x26,  0xf0,  0xfe,  0x74,  0x03,
+  0xfe,  0xa0,  0xf0,  0xfe,  0x62,  0x03,  0xfe,  0x11,  0xf0,  0xdb,  0xfe,  0x0e,  0x10,  0xfe,  0x9f,  0xf0,
+  0xfe,  0x82,  0x03,  0xef,  0x13,  0xfe,  0x11,  0x00,  0x02,  0x54,  0x38,  0xfe,  0x48,  0x1c,  0xef,  0x19,
+  0xf6,  0x35,  0xf6,  0xfe,  0x82,  0xf0,  0xfe,  0x88,  0x03,  0x24,  0x2a,  0xc4,  0x70,  0x16,  0xc4,  0x0f,
+  0x7e,  0x01,  0x15,  0x70,  0x7f,  0x07,  0x1e,  0x09,  0x51,  0x01,  0x40,  0x11,  0x3d,  0x07,  0x3d,  0x09,
+  0xa1,  0x01,  0xa0,  0xfc,  0x11,  0xfe,  0xe4,  0x00,  0x2f,  0xfe,  0xce,  0x03,  0x19,  0x32,  0x1f,  0xfe,
+  0xde,  0x03,  0x01,  0x41,  0xd4,  0xfe,  0xee,  0x03,  0x71,  0x8c,  0xd7,  0xfe,  0xae,  0x06,  0x02,  0x25,
+  0x04,  0x7d,  0x2c,  0x1a,  0xfe,  0x20,  0x05,  0x17,  0x88,  0x01,  0x2e,  0x01,  0x9b,  0x01,  0x9d,  0x35,
+  0xfe,  0x60,  0x02,  0x02,  0xf4,  0xef,  0x38,  0x86,  0x18,  0xfe,  0x67,  0x1b,  0xfe,  0xbf,  0x57,  0xf5,
+  0xfe,  0x48,  0x1c,  0x8f,  0x01,  0xf2,  0xb1,  0xfe,  0x96,  0xf0,  0xfe,  0x28,  0x04,  0x2f,  0xfe,  0x2c,
+  0x04,  0x35,  0x27,  0x0f,  0x3d,  0x01,  0x15,  0x05,  0x10,  0x1a,  0xfe,  0x0c,  0x05,  0x4c,  0x97,  0xa3,
+  0x33,  0x84,  0x74,  0x19,  0x32,  0x1f,  0x25,  0x04,  0x7d,  0x2c,  0xfe,  0x10,  0x12,  0x17,  0x88,  0x01,
+  0x2e,  0x35,  0xfe,  0x60,  0x02,  0x02,  0xf4,  0x21,  0xfe,  0xa0,  0x00,  0xfe,  0x9b,  0x57,  0xfe,  0x5e,
+  0x12,  0x0a,  0x08,  0x06,  0xfe,  0x56,  0x12,  0x23,  0x29,  0x98,  0x01,  0x0c,  0x84,  0x74,  0x1f,  0xfe,
+  0xdc,  0x04,  0x23,  0x29,  0x98,  0x01,  0x0c,  0x1f,  0x25,  0x23,  0x29,  0xba,  0xfe,  0x4c,  0x44,  0xfe,
+  0x32,  0x12,  0x50,  0xfe,  0x44,  0x48,  0x07,  0xfe,  0x93,  0x00,  0xfe,  0x4c,  0x54,  0x77,  0xfe,  0x0c,
+  0x05,  0x81,  0xa3,  0x33,  0xfe,  0x06,  0x80,  0xfe,  0x48,  0x47,  0xfe,  0x48,  0x13,  0x3e,  0x05,  0xfe,
+  0xcc,  0x00,  0xfe,  0x40,  0x13,  0x0a,  0x08,  0x06,  0xea,  0xfe,  0x06,  0x10,  0x23,  0x29,  0xba,  0x0a,
+  0x08,  0x39,  0xe1,  0x17,  0xa6,  0x0a,  0x08,  0x06,  0x59,  0x17,  0xfe,  0x0d,  0x00,  0x01,  0x2e,  0x35,
+  0xfe,  0x66,  0x0d,  0x02,  0x25,  0x3b,  0x11,  0xfe,  0xe6,  0x00,  0xfe,  0x1c,  0x90,  0xb7,  0x03,  0x17,
+  0xa6,  0x01,  0x2e,  0x35,  0x27,  0x19,  0x27,  0x02,  0xfe,  0x14,  0x05,  0xfe,  0x42,  0x5b,  0x86,  0x18,
+  0xfe,  0x46,  0x59,  0xfe,  0xbf,  0x57,  0xf5,  0x17,  0x78,  0xfe,  0x07,  0x80,  0xfe,  0x31,  0x44,  0x0a,
+  0x08,  0x0b,  0x99,  0xfe,  0x20,  0x80,  0x05,  0x18,  0xfe,  0x70,  0x12,  0x73,  0x08,  0x06,  0xfe,  0x60,
+  0x13,  0x04,  0xfe,  0xa2,  0x00,  0x2c,  0x1a,  0xfe,  0xac,  0x05,  0xfe,  0x31,  0xe4,  0x5f,  0x73,  0x08,
+  0x0b,  0xfe,  0x4a,  0x13,  0x04,  0xfe,  0xa0,  0x00,  0x2c,  0xfe,  0x42,  0x12,  0x62,  0x2f,  0xfe,  0x6c,
+  0x05,  0x19,  0x32,  0xf7,  0x01,  0x0c,  0x26,  0xfe,  0xc4,  0x05,  0x11,  0xfe,  0xe3,  0x00,  0x24,  0x73,
+  0xfe,  0x4a,  0xf0,  0xfe,  0x96,  0x05,  0xfe,  0x49,  0xf0,  0xfe,  0x90,  0x05,  0xab,  0x20,  0xfe,  0x21,
+  0x00,  0xa8,  0x20,  0xfe,  0x22,  0x00,  0xa2,  0x20,  0x8d,  0xfe,  0x09,  0x48,  0x01,  0x0c,  0x26,  0xfe,
+  0xc4,  0x05,  0xfe,  0xe2,  0x08,  0x73,  0x08,  0xe0,  0x59,  0x01,  0x99,  0x20,  0x06,  0x16,  0xe8,  0x4b,
+  0xfe,  0x27,  0x01,  0x0a,  0x08,  0x39,  0xb0,  0x46,  0x01,  0xb6,  0x17,  0xa6,  0x0a,  0x08,  0x06,  0x59,
+  0x17,  0xfe,  0x0d,  0x00,  0x01,  0x2e,  0x01,  0x9b,  0x01,  0x9d,  0x35,  0xfe,  0x66,  0x0d,  0x02,  0x25,
+  0x04,  0xfe,  0x9c,  0x00,  0x2c,  0xfe,  0x3e,  0x12,  0x04,  0x5b,  0x2c,  0xfe,  0x36,  0x13,  0x46,  0x01,
+  0xb6,  0x26,  0xfe,  0x3c,  0x06,  0x0f,  0x06,  0x73,  0x08,  0x22,  0xfe,  0x02,  0x12,  0x69,  0x01,  0xfe,
+  0xd0,  0x14,  0x1f,  0xfe,  0x32,  0x06,  0x11,  0xc8,  0x01,  0x41,  0x11,  0xfe,  0xe5,  0x00,  0x04,  0x5b,
+  0xc2,  0x0e,  0x5b,  0x04,  0xfe,  0x9e,  0x00,  0x2c,  0xfe,  0x62,  0x12,  0x04,  0x56,  0x2c,  0xf1,  0x01,
+  0xfe,  0x40,  0x19,  0x01,  0xfe,  0xaa,  0x19,  0xee,  0xd2,  0xec,  0x07,  0x6a,  0xff,  0x02,  0x00,  0x57,
+  0x6c,  0x80,  0x1b,  0x58,  0xd1,  0xd2,  0x8b,  0x46,  0x01,  0xb6,  0x26,  0xfe,  0xa6,  0x06,  0x73,  0x08,
+  0x1d,  0xa7,  0x7c,  0x0f,  0x5d,  0x01,  0xfe,  0xfe,  0x14,  0x1f,  0xfe,  0x9c,  0x06,  0x11,  0xc8,  0x01,
+  0x41,  0x11,  0xfe,  0xe5,  0x00,  0x04,  0x56,  0xc2,  0x0e,  0x56,  0x09,  0x06,  0x01,  0xb6,  0xfc,  0x76,
+  0x8f,  0x01,  0xf2,  0xb1,  0x11,  0xfe,  0xe2,  0x00,  0x2f,  0xfe,  0xbe,  0x06,  0x19,  0x32,  0xd7,  0xfe,
+  0xda,  0x06,  0x83,  0xfe,  0x78,  0x07,  0xd4,  0xfe,  0x80,  0x07,  0x71,  0x8c,  0x02,  0x25,  0x0a,  0x08,
+  0x0b,  0xfe,  0x2e,  0x12,  0x14,  0x18,  0x01,  0x0c,  0x14,  0x00,  0x01,  0x0c,  0x14,  0x00,  0x01,  0x0c,
+  0x14,  0x00,  0x01,  0x0c,  0xfe,  0x99,  0xa4,  0x01,  0x0c,  0x14,  0x00,  0x02,  0xfe,  0x3e,  0x08,  0x6f,
+  0x08,  0x1d,  0xea,  0x0a,  0x08,  0x1d,  0xfe,  0x30,  0x13,  0x14,  0xfe,  0x1b,  0x00,  0x01,  0x0c,  0x14,
+  0x00,  0x01,  0x0c,  0x14,  0x00,  0x01,  0x0c,  0x14,  0x00,  0x01,  0x0c,  0x14,  0x06,  0x01,  0x0c,  0x14,
+  0x00,  0x02,  0xfe,  0xe6,  0x0b,  0x69,  0xfe,  0x9a,  0x81,  0x6d,  0x8d,  0xfe,  0x09,  0x6f,  0xfe,  0x93,
+  0x45,  0x1a,  0xfe,  0x88,  0x07,  0x2f,  0xfe,  0x60,  0x07,  0x19,  0x32,  0xd7,  0xfe,  0x58,  0x07,  0x71,
+  0x8c,  0x83,  0xfe,  0x78,  0x07,  0x02,  0x25,  0x01,  0x41,  0x02,  0xfe,  0xbe,  0x06,  0x14,  0x22,  0x02,
+  0xfe,  0xbe,  0x06,  0xfe,  0x9c,  0xf7,  0xfe,  0xf4,  0x07,  0xfe,  0x2c,  0x90,  0xfe,  0xae,  0x90,  0x52,
+  0xfe,  0xd6,  0x07,  0x0e,  0x65,  0x12,  0x66,  0x0a,  0x4f,  0x5f,  0x3a,  0x01,  0xfe,  0xd6,  0x18,  0x05,
+  0x10,  0x85,  0xfe,  0x83,  0xe7,  0xfe,  0x95,  0x00,  0xa8,  0xfe,  0x03,  0x40,  0x0a,  0x4f,  0x78,  0x3a,
+  0x01,  0xbc,  0xb5,  0xfe,  0x1f,  0x40,  0x16,  0x67,  0x01,  0xf8,  0xfe,  0x08,  0x50,  0xfe,  0x8a,  0x50,
+  0xfe,  0x34,  0x51,  0xfe,  0xb6,  0x51,  0xfe,  0x08,  0x90,  0xfe,  0x8a,  0x90,  0x0e,  0x63,  0x12,  0x64,
+  0xfe,  0x0c,  0x90,  0xfe,  0x8e,  0x90,  0xfe,  0x28,  0x50,  0xfe,  0xaa,  0x50,  0x0e,  0x42,  0x12,  0x43,
+  0x41,  0x0a,  0x08,  0x5f,  0xb0,  0xfe,  0x2c,  0x90,  0xfe,  0xae,  0x90,  0x0e,  0x65,  0x12,  0x66,  0x0a,
+  0x08,  0x78,  0xd1,  0x01,  0xbc,  0xfe,  0x1f,  0x80,  0x16,  0x67,  0xfe,  0x34,  0x90,  0xfe,  0xb6,  0x90,
+  0x0e,  0x44,  0x12,  0x45,  0xfe,  0x08,  0x90,  0xfe,  0x8a,  0x90,  0x0e,  0x63,  0x12,  0x64,  0xfe,  0x28,
+  0x90,  0xfe,  0xaa,  0x90,  0x0e,  0x42,  0x12,  0x43,  0x0e,  0x31,  0x12,  0x3f,  0x24,  0x0e,  0x53,  0x0e,
+  0x68,  0x0a,  0x4f,  0x22,  0x3a,  0x38,  0x07,  0xa5,  0x2f,  0xfe,  0x5e,  0x08,  0xfe,  0x9e,  0xf0,  0xfe,
+  0x72,  0x08,  0xcc,  0x1a,  0x32,  0x38,  0x72,  0xfe,  0xed,  0x10,  0xaa,  0xfe,  0x96,  0x08,  0xac,  0xfe,
+  0xb2,  0x08,  0x83,  0xfe,  0x8a,  0x08,  0xd4,  0xfe,  0x90,  0x08,  0x71,  0x8c,  0x02,  0x25,  0x01,  0x41,
+  0xfe,  0xc9,  0x10,  0x14,  0x22,  0xfe,  0xc9,  0x10,  0x6f,  0x08,  0x06,  0xfe,  0x10,  0x12,  0x6f,  0x08,
+  0x0b,  0x4e,  0x0a,  0x08,  0x0b,  0xfe,  0x8e,  0x12,  0xfe,  0x2e,  0x1c,  0xad,  0x6f,  0x08,  0x06,  0x4e,
+  0x6f,  0x08,  0x0b,  0xfe,  0x7a,  0x12,  0xfe,  0x2c,  0x1c,  0xfe,  0xaa,  0xf0,  0xfe,  0xcc,  0x09,  0xfe,
+  0xac,  0xf0,  0xfe,  0xfa,  0x08,  0x02,  0xfe,  0xd8,  0x09,  0xfe,  0xb7,  0xf0,  0xfe,  0xf6,  0x08,  0xfe,
+  0x02,  0xf6,  0x1d,  0x69,  0xfe,  0x70,  0x18,  0xfe,  0xf1,  0x18,  0xfe,  0x40,  0x55,  0xfe,  0xe1,  0x55,
+  0xfe,  0x10,  0x58,  0xfe,  0x91,  0x58,  0xfe,  0x14,  0x59,  0xfe,  0x95,  0x59,  0x19,  0x92,  0xfe,  0x8c,
+  0xf0,  0xfe,  0xf6,  0x08,  0xfe,  0xac,  0xf0,  0xfe,  0xea,  0x08,  0xfe,  0x34,  0x1c,  0xfe,  0xcb,  0x10,
+  0xfe,  0xad,  0xf0,  0xfe,  0x06,  0x09,  0x02,  0xfe,  0x12,  0x0b,  0xfe,  0x36,  0x1c,  0xfe,  0xbf,  0x10,
+  0xfe,  0x2b,  0xf0,  0x92,  0xfe,  0x6b,  0x18,  0x1b,  0xfe,  0x00,  0xfe,  0xe1,  0xcd,  0xfe,  0xd2,  0xf0,
+  0x92,  0xfe,  0x76,  0x18,  0x1b,  0x18,  0x1a,  0x92,  0x04,  0xe7,  0x1b,  0x06,  0x1a,  0x92,  0xaa,  0x57,
+  0xac,  0x57,  0xfe,  0x34,  0x1c,  0xfe,  0x36,  0x1c,  0xfe,  0x89,  0x10,  0x8f,  0x62,  0x3b,  0x17,  0xa6,
+  0x01,  0x2e,  0x13,  0xfe,  0x35,  0x00,  0x35,  0x54,  0x13,  0x90,  0x02,  0x54,  0xf9,  0xaf,  0x0b,  0xfe,
+  0x1a,  0x12,  0x50,  0xfe,  0x19,  0x82,  0xfe,  0x6c,  0x18,  0xfe,  0x44,  0x54,  0xeb,  0xde,  0xfe,  0x74,
+  0x18,  0x91,  0x93,  0x1a,  0xfe,  0xc8,  0x08,  0x02,  0x57,  0x0a,  0x08,  0x5f,  0x2e,  0x04,  0x31,  0x2b,
+  0x3f,  0x0e,  0x44,  0x12,  0x45,  0x82,  0x31,  0x5a,  0x3f,  0xfe,  0x6c,  0x18,  0xfe,  0xed,  0x18,  0xfe,
+  0x44,  0x54,  0xfe,  0xe5,  0x54,  0x36,  0x44,  0x21,  0x45,  0x04,  0x53,  0x2b,  0x68,  0x91,  0xfe,  0xe3,
+  0x54,  0xfe,  0x74,  0x18,  0xfe,  0xf5,  0x18,  0x91,  0xfe,  0xe3,  0x54,  0x93,  0xc9,  0x52,  0xfe,  0xc8,
+  0x08,  0x02,  0x57,  0xfe,  0x37,  0xf0,  0xfe,  0xd4,  0x09,  0xfe,  0x8b,  0xf0,  0xfe,  0x5a,  0x09,  0x02,
+  0x57,  0xf9,  0xaf,  0x0b,  0x28,  0xfe,  0xf4,  0x0a,  0x36,  0x53,  0x21,  0x68,  0x52,  0xfe,  0x38,  0x0a,
+  0x07,  0xfe,  0xc0,  0x07,  0x46,  0x61,  0x00,  0xd9,  0xfe,  0x01,  0x59,  0xfe,  0x52,  0xf0,  0xfe,  0x06,
+  0x0a,  0x91,  0x96,  0xfe,  0x1e,  0x0a,  0x36,  0x53,  0x91,  0xfe,  0xe3,  0x54,  0x4d,  0x53,  0x6e,  0x68,
+  0xfe,  0x14,  0x58,  0xfe,  0x95,  0x58,  0x02,  0x57,  0x36,  0x53,  0x21,  0x68,  0xfe,  0x14,  0x59,  0xfe,
+  0x95,  0x59,  0xeb,  0x4d,  0x53,  0x4d,  0x68,  0x02,  0x57,  0x0a,  0x08,  0x5f,  0xfe,  0x82,  0x12,  0x0a,
+  0x08,  0x22,  0xfe,  0x66,  0x13,  0x2a,  0x67,  0x70,  0xd0,  0xfe,  0x83,  0x80,  0xfe,  0xc8,  0x44,  0xfe,
+  0x2e,  0x13,  0xfe,  0x04,  0x91,  0xfe,  0x86,  0x91,  0x6b,  0x33,  0xfe,  0x40,  0x59,  0xfe,  0xc1,  0x59,
+  0x52,  0xfe,  0xd0,  0x08,  0x04,  0x65,  0x2b,  0x66,  0x0e,  0xb3,  0x12,  0x90,  0x4d,  0x65,  0x6e,  0x66,
+  0x01,  0xbc,  0xb5,  0x6b,  0x33,  0x16,  0x67,  0x82,  0x31,  0x5a,  0x3f,  0x36,  0x44,  0x21,  0x45,  0x93,
+  0xc9,  0xfe,  0x04,  0xfa,  0x31,  0xfe,  0x05,  0xfa,  0x3f,  0x01,  0xf8,  0xfe,  0x36,  0x10,  0x24,  0x0e,
+  0xb3,  0x0e,  0x90,  0x36,  0x44,  0x21,  0x45,  0xad,  0x0a,  0x08,  0x22,  0x1a,  0xfe,  0xd0,  0x08,  0x36,
+  0x42,  0x21,  0x43,  0x0a,  0x08,  0xfe,  0xf7,  0x00,  0x3a,  0x04,  0x63,  0x2b,  0x64,  0xfe,  0x10,  0x58,
+  0xfe,  0x91,  0x58,  0x4d,  0x53,  0x6e,  0x68,  0x02,  0xfe,  0xee,  0x09,  0x0a,  0x08,  0x22,  0x1a,  0xfe,
+  0xd0,  0x08,  0x0a,  0x08,  0xfe,  0xf7,  0x00,  0x3a,  0xeb,  0xde,  0x69,  0xfe,  0x10,  0x90,  0xfe,  0x92,
+  0x90,  0xfe,  0xd3,  0x10,  0x3e,  0x05,  0xca,  0x1a,  0xfe,  0x02,  0x09,  0x11,  0xca,  0xf9,  0xaf,  0x0b,
+  0xfe,  0x14,  0x13,  0x04,  0x42,  0x2b,  0x43,  0x52,  0xfe,  0x02,  0x09,  0xfe,  0x0c,  0x58,  0xfe,  0x8d,
+  0x58,  0x02,  0x57,  0x24,  0x46,  0xfe,  0x19,  0x80,  0xfe,  0xf1,  0x10,  0x0a,  0x08,  0x0b,  0xa7,  0xfe,
+  0x6c,  0x19,  0xfe,  0x19,  0x41,  0xfe,  0x94,  0x10,  0xfe,  0x6c,  0x19,  0x4d,  0x42,  0xfe,  0xed,  0x19,
+  0x6e,  0x43,  0xfe,  0x0c,  0x51,  0xfe,  0x8e,  0x51,  0xfe,  0x6b,  0x18,  0x1b,  0xfe,  0x00,  0xff,  0x30,
+  0xfe,  0x7a,  0x10,  0xcd,  0xfe,  0xd2,  0xf0,  0xfe,  0x8c,  0x0b,  0xfe,  0x76,  0x18,  0x1b,  0x18,  0xa9,
+  0x04,  0xe7,  0x1b,  0x06,  0x87,  0x13,  0xfe,  0x16,  0x00,  0x02,  0x54,  0xfe,  0xd1,  0xf0,  0xfe,  0xc2,
+  0x0b,  0x17,  0xa5,  0x01,  0x2e,  0x13,  0xfe,  0x17,  0x00,  0xfe,  0x48,  0x10,  0xfe,  0xce,  0xf0,  0xfe,
+  0xaa,  0x0b,  0x13,  0xfe,  0x21,  0x00,  0x02,  0x54,  0xfe,  0xcd,  0xf0,  0xfe,  0xb6,  0x0b,  0x13,  0xfe,
+  0x22,  0x00,  0x02,  0x54,  0xfe,  0xcb,  0xf0,  0xfe,  0xc2,  0x0b,  0x13,  0xfe,  0x24,  0x00,  0x02,  0x54,
+  0xfe,  0xd0,  0xf0,  0xfe,  0xcc,  0x0b,  0x13,  0xae,  0xdf,  0xfe,  0xcf,  0xf0,  0xfe,  0xd6,  0x0b,  0x13,
+  0x8d,  0xdc,  0xfe,  0xcc,  0xf0,  0xfe,  0xe6,  0x0b,  0xfe,  0x84,  0x80,  0xaf,  0x22,  0xfe,  0xd5,  0x12,
+  0x13,  0xfe,  0x12,  0x00,  0x2f,  0xfe,  0xe6,  0x0b,  0x19,  0x32,  0xaa,  0x25,  0xac,  0x25,  0x38,  0xfc,
+  0x2f,  0xfe,  0xfa,  0x0b,  0x19,  0x32,  0x83,  0xfe,  0x16,  0x0c,  0x71,  0x8c,  0xaa,  0xfe,  0xf4,  0x07,
+  0xac,  0xfe,  0xf4,  0x07,  0x02,  0x25,  0x01,  0x41,  0xfe,  0xdb,  0x10,  0x11,  0xfe,  0xe8,  0x00,  0x8f,
+  0x84,  0x74,  0xfe,  0x89,  0xf0,  0x25,  0x23,  0x29,  0xfe,  0xe9,  0x09,  0x01,  0x0c,  0x84,  0x74,  0x1f,
+  0x25,  0x23,  0x29,  0x98,  0x35,  0xfe,  0x4e,  0x0c,  0x19,  0x32,  0x02,  0xfe,  0x42,  0x0c,  0xcc,  0x4e,
+  0x13,  0xfe,  0x42,  0x00,  0x02,  0x54,  0xa4,  0x06,  0xfe,  0x81,  0x49,  0xfe,  0xcc,  0x12,  0x0a,  0x08,
+  0x0b,  0xf1,  0x13,  0x00,  0x60,  0x0b,  0xfe,  0x6a,  0x12,  0x60,  0xfe,  0x28,  0x00,  0x28,  0xfe,  0x94,
+  0x0d,  0x0f,  0x7e,  0x01,  0x15,  0x05,  0x00,  0x87,  0x37,  0xfe,  0x28,  0x00,  0x02,  0xfe,  0x94,  0x0d,
+  0x01,  0x9b,  0x01,  0x9d,  0x0f,  0xc7,  0x01,  0xfe,  0xf0,  0x0e,  0xb9,  0x07,  0x3d,  0x09,  0xa1,  0x01,
+  0x40,  0x11,  0x48,  0x07,  0x1e,  0x09,  0x51,  0x01,  0x79,  0x02,  0x27,  0x13,  0xfe,  0x44,  0x00,  0x60,
+  0x0b,  0xa7,  0x37,  0x0b,  0xfe,  0xc0,  0x10,  0x01,  0x99,  0x37,  0x0b,  0xfe,  0xb6,  0x10,  0x01,  0x99,
+  0xfe,  0x19,  0x82,  0xfe,  0x34,  0x46,  0xfe,  0x0a,  0x13,  0x37,  0x0b,  0x13,  0xfe,  0x43,  0x00,  0xc0,
+  0x0a,  0x4f,  0x0b,  0x3a,  0x01,  0x9b,  0x01,  0x9d,  0xb9,  0x07,  0x3d,  0x09,  0xa1,  0x01,  0x40,  0x11,
+  0x48,  0x07,  0x1e,  0x09,  0x51,  0x01,  0x79,  0x86,  0x0b,  0xb9,  0x1c,  0xd3,  0x02,  0xfe,  0x4c,  0x03,
+  0x0a,  0x08,  0x0b,  0xa9,  0x37,  0x0b,  0x13,  0x00,  0xfe,  0x54,  0x10,  0x6f,  0x08,  0x1d,  0xfe,  0x50,
+  0x12,  0x0a,  0x08,  0x1d,  0xfe,  0x48,  0x13,  0xfe,  0x1c,  0x1c,  0xfe,  0x9d,  0xf0,  0xfe,  0x52,  0x0d,
+  0xfe,  0x1c,  0x1c,  0xfe,  0x9d,  0xf0,  0xfe,  0x58,  0x0d,  0x0a,  0x4f,  0x1d,  0x3a,  0xfe,  0x95,  0x10,
+  0x13,  0xfe,  0x15,  0x00,  0xfe,  0x04,  0xe6,  0x0b,  0x69,  0xfe,  0x26,  0x10,  0x13,  0xfe,  0x13,  0x00,
+  0xdc,  0x13,  0xfe,  0x47,  0x00,  0xa8,  0x13,  0xfe,  0x41,  0x00,  0xa2,  0x13,  0xfe,  0x24,  0x00,  0x04,
+  0x7d,  0x2c,  0x28,  0xf4,  0x69,  0xfe,  0x04,  0xe6,  0x1d,  0xfe,  0x9d,  0x41,  0xfe,  0x1c,  0x42,  0xb9,
+  0x01,  0xfe,  0xf8,  0x0e,  0x02,  0x27,  0xdd,  0x17,  0x0b,  0x4b,  0xfb,  0xe5,  0x17,  0xfe,  0x31,  0x00,
+  0x4b,  0xc3,  0x01,  0xfe,  0xfc,  0x0f,  0x02,  0xfe,  0xc6,  0x01,  0x1c,  0xfe,  0x06,  0xec,  0xfe,  0xb9,
+  0x00,  0x89,  0x37,  0x39,  0xc6,  0x30,  0x1c,  0xfe,  0x06,  0xea,  0xfe,  0xb9,  0x00,  0xfe,  0x47,  0x4b,
+  0x7c,  0xfe,  0x75,  0x57,  0x04,  0x5e,  0xfe,  0x98,  0x56,  0xfe,  0x28,  0x12,  0x0f,  0x7e,  0xfe,  0xfa,
+  0x14,  0x46,  0xed,  0x0f,  0xc7,  0xfe,  0xf0,  0x14,  0xfe,  0x49,  0x54,  0x95,  0xfe,  0x08,  0x0e,  0x0f,
+  0x1e,  0xfe,  0xe4,  0x14,  0xfe,  0x44,  0x48,  0x02,  0xfe,  0x4c,  0x03,  0x0f,  0x5e,  0xfe,  0xc8,  0x14,
+  0x89,  0x37,  0x39,  0xc6,  0x30,  0x1c,  0xfe,  0xce,  0x47,  0xfe,  0xbd,  0x13,  0x02,  0x27,  0x2a,  0x2d,
+  0x05,  0x10,  0xfe,  0x78,  0x12,  0x24,  0x16,  0x5d,  0x16,  0xb2,  0x2a,  0x48,  0x46,  0x4b,  0x48,  0xcc,
+  0xd9,  0xfe,  0xbc,  0xf0,  0xfe,  0xa4,  0x0e,  0x07,  0x06,  0x16,  0x5d,  0x01,  0xfe,  0xb0,  0x16,  0x04,
+  0xfe,  0x38,  0x01,  0x2b,  0xfe,  0x3a,  0x01,  0x52,  0xfe,  0xa8,  0x0e,  0x04,  0xfe,  0x38,  0x01,  0x1b,
+  0xfe,  0xf0,  0xff,  0x0e,  0xfe,  0x60,  0x01,  0x04,  0xfe,  0x3a,  0x01,  0x0e,  0xfe,  0x62,  0x01,  0x20,
+  0x06,  0x16,  0x48,  0xfe,  0x04,  0xec,  0x2d,  0x07,  0x2d,  0x09,  0x3c,  0x1c,  0x01,  0x40,  0x81,  0xfe,
+  0x05,  0xf6,  0xfe,  0x34,  0x01,  0x01,  0xfe,  0x20,  0x17,  0x11,  0x48,  0xd3,  0x07,  0x06,  0x03,  0x24,
+  0x03,  0x2a,  0x5d,  0xfe,  0xf7,  0x12,  0x2a,  0xb2,  0x70,  0x16,  0xb2,  0x05,  0xa5,  0xfe,  0x93,  0x13,
+  0xfe,  0x24,  0x1c,  0x17,  0x18,  0x4b,  0xfb,  0xe5,  0xfe,  0xd9,  0x10,  0x9a,  0xfe,  0x03,  0xdc,  0xfe,
+  0x73,  0x57,  0xfe,  0x80,  0x5d,  0x03,  0x9a,  0xfe,  0x03,  0xdc,  0x24,  0xfe,  0x70,  0x57,  0xfe,  0x33,
+  0x54,  0xfe,  0x3b,  0x54,  0xfe,  0x80,  0x5d,  0x03,  0xfe,  0x03,  0x57,  0x9a,  0x24,  0xfe,  0x00,  0xcc,
+  0x03,  0xfe,  0x03,  0x57,  0x9a,  0x7f,  0x03,  0x01,  0xfe,  0x50,  0x17,  0x3e,  0x05,  0x48,  0xfe,  0x0a,
+  0x13,  0x07,  0x1e,  0x09,  0x51,  0xdc,  0x01,  0x9b,  0x01,  0x9d,  0x07,  0x3d,  0x09,  0xa1,  0x01,  0x40,
+  0x11,  0xfe,  0xe9,  0x00,  0x0a,  0x08,  0x8d,  0xfe,  0x52,  0x13,  0x01,  0xfe,  0xe2,  0x16,  0xfe,  0x1e,
+  0x1c,  0xfe,  0x14,  0x90,  0x0e,  0xfe,  0x64,  0x01,  0xfe,  0x16,  0x90,  0x0e,  0xfe,  0x66,  0x01,  0x0a,
+  0x08,  0x78,  0xea,  0xfe,  0x03,  0x80,  0x72,  0x4c,  0x11,  0x7b,  0x07,  0x2d,  0x09,  0x3c,  0x1c,  0x97,
+  0x01,  0xa0,  0xfe,  0x62,  0x08,  0x70,  0x4c,  0x11,  0x7b,  0x07,  0x2d,  0x09,  0x3c,  0x1c,  0x97,  0x01,
+  0xa0,  0x6b,  0x33,  0x11,  0x7b,  0x07,  0x2d,  0x09,  0x3c,  0x1c,  0x97,  0x01,  0x79,  0x03,  0xfe,  0x08,
+  0x1c,  0x04,  0xfe,  0xac,  0x00,  0xfe,  0x06,  0x58,  0x04,  0xfe,  0xae,  0x00,  0xfe,  0x07,  0x58,  0x04,
+  0xfe,  0xb0,  0x00,  0xfe,  0x08,  0x58,  0x04,  0xfe,  0xb2,  0x00,  0xfe,  0x09,  0x58,  0xfe,  0x0a,  0x1c,
+  0x20,  0x8b,  0x16,  0xfe,  0xb9,  0x00,  0x24,  0x0e,  0x5b,  0x0e,  0x56,  0x20,  0x10,  0x16,  0x2d,  0x16,
+  0x3c,  0x50,  0xa4,  0xfe,  0x93,  0x00,  0x07,  0x2d,  0x09,  0x3c,  0x1c,  0x01,  0x79,  0x81,  0x11,  0x7b,
+  0xfe,  0x14,  0x56,  0xfe,  0xd6,  0xf0,  0xfe,  0xd6,  0x0f,  0xdd,  0x8f,  0xfe,  0x14,  0x1c,  0xfe,  0x10,
+  0x1c,  0xfe,  0x18,  0x1c,  0x03,  0x1c,  0xfe,  0x0c,  0x14,  0x89,  0xfe,  0x07,  0xe6,  0x39,  0xfe,  0xce,
+  0x47,  0xfe,  0xf5,  0x13,  0x03,  0x01,  0x99,  0x0f,  0x3d,  0x01,  0x15,  0x05,  0x10,  0xda,  0x0f,  0x1e,
+  0x01,  0x15,  0x05,  0x10,  0xe1,  0xfe,  0x44,  0x58,  0x4c,  0xfe,  0x01,  0xec,  0xc3,  0xfe,  0x9e,  0x40,
+  0xfe,  0x9d,  0xe7,  0x00,  0xfe,  0x9c,  0xe7,  0x1d,  0xa3,  0x33,  0x01,  0xfe,  0xf8,  0x0e,  0xfe,  0xc9,
+  0x10,  0x03,  0x38,  0x84,  0x74,  0x23,  0x29,  0xba,  0x05,  0x1d,  0xfe,  0x48,  0x12,  0x05,  0x0b,  0xfe,
+  0x4c,  0x12,  0x05,  0x18,  0xfe,  0x30,  0x12,  0x05,  0xd5,  0x1a,  0xfe,  0xa0,  0x11,  0x05,  0xfe,  0x23,
+  0x00,  0x1a,  0xfe,  0xac,  0x11,  0x05,  0x06,  0x1a,  0xa9,  0x05,  0x22,  0xfe,  0x12,  0x12,  0x05,  0x00,
+  0x1a,  0x25,  0x17,  0xd5,  0x01,  0x2e,  0xce,  0x3b,  0x01,  0x0c,  0x83,  0x41,  0x03,  0x3b,  0x11,  0xfe,
+  0xcc,  0x00,  0x02,  0x27,  0x3b,  0x3e,  0x05,  0xca,  0xfe,  0xe3,  0x13,  0x36,  0x42,  0x21,  0x43,  0x52,
+  0xfe,  0x5e,  0x11,  0x0a,  0x08,  0x5f,  0xfe,  0x72,  0x12,  0x82,  0x31,  0x5a,  0x3f,  0x93,  0xc9,  0x95,
+  0xfe,  0x28,  0x11,  0x2a,  0x67,  0xfe,  0x26,  0x13,  0x04,  0xb3,  0x2b,  0x90,  0x52,  0xfe,  0x78,  0x0d,
+  0x0e,  0x65,  0x12,  0x66,  0x24,  0x0e,  0xb3,  0x0e,  0x90,  0x01,  0xbc,  0x20,  0x8b,  0x72,  0x16,  0x67,
+  0x01,  0xf8,  0x82,  0x31,  0x5a,  0x3f,  0xfe,  0x04,  0x55,  0xfe,  0xa5,  0x55,  0xfe,  0x04,  0xfa,  0x31,
+  0xfe,  0x05,  0xfa,  0x3f,  0xfe,  0x91,  0x10,  0x04,  0x44,  0x2b,  0x45,  0xfe,  0x40,  0x56,  0xfe,  0xe1,
+  0x56,  0x0e,  0x44,  0x12,  0x45,  0xab,  0x82,  0x31,  0x5a,  0x3f,  0x93,  0xc9,  0x04,  0x63,  0x2b,  0x64,
+  0xfe,  0x00,  0x56,  0xfe,  0xa1,  0x56,  0x0e,  0x63,  0x12,  0x64,  0x0a,  0x08,  0x5f,  0xfe,  0x1e,  0x12,
+  0x2a,  0x67,  0xfe,  0x1f,  0x40,  0x04,  0x65,  0x2b,  0x66,  0xfe,  0x2c,  0x50,  0xfe,  0xae,  0x50,  0x04,
+  0x44,  0x2b,  0x45,  0xfe,  0x34,  0x50,  0xfe,  0xb6,  0x50,  0x04,  0x63,  0x2b,  0x64,  0xfe,  0x08,  0x50,
+  0xfe,  0x8a,  0x50,  0x04,  0x42,  0x2b,  0x43,  0xfe,  0x28,  0x50,  0xfe,  0xaa,  0x50,  0x02,  0x9c,  0x20,
+  0x06,  0x16,  0xfa,  0x02,  0x7a,  0x3b,  0x01,  0x0c,  0x1f,  0x55,  0x23,  0x29,  0xba,  0x05,  0x06,  0x28,
+  0x55,  0x3e,  0x05,  0xca,  0x28,  0x7a,  0x01,  0xf2,  0x1b,  0x58,  0x1a,  0x55,  0x0a,  0x08,  0x0b,  0xe4,
+  0x36,  0x42,  0x21,  0x43,  0xfe,  0x0a,  0x55,  0x30,  0xfe,  0x8b,  0x55,  0x4d,  0x42,  0x6e,  0x43,  0xfe,
+  0x0c,  0x51,  0xfe,  0x8e,  0x51,  0x02,  0x7a,  0xde,  0xfe,  0x0a,  0x45,  0xfe,  0x19,  0x41,  0x02,  0x7a,
+  0x3b,  0x01,  0x0c,  0x1f,  0xc0,  0x23,  0x29,  0xfe,  0xe9,  0x09,  0x60,  0x18,  0xfe,  0x94,  0x12,  0x60,
+  0x0b,  0x59,  0x02,  0x55,  0x2f,  0xb0,  0x19,  0x32,  0x1f,  0xc0,  0x23,  0x29,  0x98,  0x05,  0x18,  0x28,
+  0x55,  0x01,  0x0c,  0x1f,  0xc0,  0x23,  0x29,  0xfe,  0xe8,  0x09,  0x50,  0x04,  0xfe,  0x9c,  0x00,  0x2c,
+  0x30,  0xfe,  0xbb,  0x45,  0x60,  0x00,  0x4e,  0x37,  0x06,  0xa4,  0x58,  0xfe,  0xc0,  0x14,  0xfe,  0xf8,
+  0x14,  0xb1,  0x3e,  0x05,  0xc8,  0xfe,  0x16,  0x13,  0x04,  0xfe,  0x9e,  0x00,  0x2c,  0xa9,  0x04,  0x56,
+  0x2c,  0x30,  0x62,  0x02,  0x7a,  0xfe,  0xc0,  0x5d,  0xfe,  0xe4,  0x14,  0xfe,  0x03,  0x17,  0x04,  0x5b,
+  0xc2,  0x0e,  0x5b,  0x62,  0x3b,  0x01,  0x0c,  0x26,  0x9c,  0x01,  0xfe,  0xd0,  0x14,  0x02,  0x9c,  0x2f,
+  0xfe,  0xb4,  0x12,  0x19,  0x32,  0x1f,  0x55,  0x23,  0x29,  0x98,  0x05,  0x06,  0x28,  0x55,  0xfe,  0xf6,
+  0x14,  0xfe,  0x42,  0x58,  0xfe,  0x70,  0x14,  0xfe,  0x92,  0x14,  0xb1,  0xfe,  0x4a,  0xf4,  0x0b,  0x1a,
+  0x55,  0xfe,  0x4a,  0xf4,  0x06,  0xd8,  0x3e,  0x05,  0xc8,  0xd1,  0x02,  0x7a,  0x04,  0x56,  0xc2,  0x0e,
+  0x56,  0x62,  0x3b,  0x01,  0x0c,  0x26,  0x9c,  0x01,  0xfe,  0xfe,  0x14,  0x02,  0x9c,  0x26,  0xe2,  0x76,
+  0xf7,  0x76,  0x03,  0x35,  0xfe,  0x18,  0x13,  0x71,  0xfe,  0x18,  0x13,  0x62,  0x3b,  0x01,  0x0c,  0xfe,
+  0xe3,  0x10,  0x07,  0x6a,  0xff,  0x02,  0x00,  0x57,  0x6c,  0x80,  0x1b,  0xfe,  0xff,  0x7f,  0xfe,  0x30,
+  0x56,  0xfe,  0x00,  0x5c,  0x03,  0x07,  0x6a,  0xff,  0x02,  0x00,  0x57,  0x6c,  0x80,  0x1b,  0x58,  0xfe,
+  0x30,  0x56,  0xfe,  0x00,  0x5c,  0x03,  0x07,  0x6a,  0xff,  0x02,  0x00,  0x57,  0x6c,  0x80,  0x03,  0x07,
+  0x6a,  0xff,  0x02,  0x00,  0x57,  0x6c,  0x80,  0xfe,  0x0b,  0x58,  0x03,  0x0f,  0x5b,  0x01,  0x9f,  0x0f,
+  0x56,  0x01,  0x9f,  0x03,  0xd0,  0x1b,  0x10,  0xff,  0x03,  0x00,  0x54,  0xfe,  0x00,  0xf4,  0x22,  0x6c,
+  0xfe,  0x00,  0x7d,  0xfe,  0x01,  0x7d,  0xfe,  0x02,  0x7d,  0xfe,  0x03,  0x7c,  0x6b,  0x33,  0x0e,  0x63,
+  0x12,  0x64,  0x4d,  0x44,  0x6e,  0x45,  0x03,  0xfe,  0x62,  0x18,  0xfe,  0x82,  0x5a,  0xfe,  0xe1,  0x1a,
+  0xbe,  0xfe,  0x02,  0x58,  0x03,  0x01,  0xfe,  0x40,  0x19,  0xfe,  0x42,  0x48,  0x69,  0x50,  0x7c,  0x01,
+  0x0c,  0x1f,  0xfe,  0xc8,  0x14,  0x23,  0x29,  0xfe,  0xe9,  0x09,  0xfe,  0xc1,  0x59,  0x01,  0x0c,  0x1f,
+  0xfe,  0xc8,  0x14,  0x23,  0x29,  0xfe,  0xe8,  0x0a,  0x04,  0xfe,  0x9e,  0x00,  0x2c,  0xfe,  0xc2,  0x12,
+  0x24,  0xb8,  0x1d,  0xe4,  0x60,  0xd6,  0x77,  0xfe,  0x18,  0x14,  0x59,  0x07,  0x06,  0x09,  0xd6,  0xa4,
+  0xfe,  0x00,  0x10,  0xfe,  0x78,  0x10,  0xff,  0x02,  0x83,  0x55,  0xa8,  0xff,  0x02,  0x83,  0x55,  0xb8,
+  0x18,  0xfe,  0x12,  0x13,  0x61,  0xfe,  0x30,  0x00,  0x95,  0xf3,  0x09,  0x88,  0x07,  0x06,  0xfe,  0x56,
+  0x10,  0xb8,  0x0b,  0xfe,  0x16,  0x13,  0x61,  0xfe,  0x64,  0x00,  0x95,  0xf3,  0x0f,  0xfe,  0x64,  0x00,
+  0x09,  0xae,  0x07,  0x06,  0xfe,  0x28,  0x10,  0xb8,  0x06,  0xfe,  0x5e,  0x13,  0x61,  0xfe,  0xc8,  0x00,
+  0x95,  0xf3,  0x0f,  0xfe,  0xc8,  0x00,  0x09,  0x5d,  0x07,  0x06,  0xab,  0x61,  0xfe,  0x90,  0x01,  0x96,
+  0xfe,  0x7e,  0x14,  0x7c,  0xad,  0xfe,  0x43,  0xf4,  0xb2,  0xfe,  0x56,  0xf0,  0xfe,  0x90,  0x14,  0xfe,
+  0x04,  0xf4,  0x6a,  0xfe,  0x43,  0xf4,  0xae,  0xfe,  0xf3,  0x10,  0xb7,  0x01,  0xf1,  0x1b,  0x58,  0xda,
+  0xfe,  0x00,  0x17,  0xfe,  0x4d,  0xe4,  0x8b,  0x96,  0xfe,  0xc2,  0x14,  0x7c,  0xfe,  0x14,  0x10,  0xfe,
+  0x00,  0x17,  0xfe,  0x4d,  0xe4,  0xec,  0x96,  0xfe,  0xc2,  0x14,  0xd2,  0xec,  0xa2,  0x50,  0x7c,  0x07,
+  0x06,  0xfe,  0xb4,  0x56,  0xfe,  0xc3,  0x58,  0x03,  0x50,  0x07,  0x0b,  0x03,  0x14,  0x06,  0x01,  0x0c,
+  0x26,  0xfe,  0xfc,  0x14,  0x14,  0x0b,  0x01,  0x0c,  0x26,  0xfe,  0xfc,  0x14,  0x14,  0x18,  0x01,  0x0c,
+  0x26,  0xfe,  0xfc,  0x14,  0x76,  0xfe,  0x89,  0x49,  0x01,  0x0c,  0x03,  0x14,  0x06,  0x01,  0x0c,  0x26,
+  0xb4,  0x14,  0x18,  0x01,  0x0c,  0x26,  0xb4,  0x14,  0x06,  0x01,  0x0c,  0x26,  0xb4,  0xfe,  0x89,  0x49,
+  0x01,  0x0c,  0x26,  0xb4,  0x76,  0xfe,  0x89,  0x4a,  0x01,  0x0c,  0x03,  0x50,  0x03,  0x2a,  0xe8,  0x05,
+  0x06,  0xfe,  0x44,  0x13,  0xb5,  0x16,  0xe8,  0xfe,  0x49,  0xf4,  0x00,  0x59,  0x76,  0xce,  0x62,  0xfe,
+  0x01,  0xec,  0xfe,  0x27,  0x01,  0xf7,  0x01,  0x0c,  0x3e,  0x05,  0xfe,  0xe3,  0x00,  0xfe,  0x20,  0x13,
+  0x1f,  0xfe,  0x80,  0x15,  0x24,  0x16,  0xfa,  0x01,  0x41,  0x2a,  0xfa,  0x05,  0x06,  0x4e,  0x0a,  0x4f,
+  0x06,  0x3a,  0x03,  0x0e,  0x5c,  0x12,  0x8e,  0xfe,  0x43,  0x58,  0x01,  0x15,  0x05,  0x10,  0xfe,  0x1e,
+  0x12,  0x49,  0xee,  0x94,  0x01,  0x47,  0xfe,  0x90,  0x4d,  0xe6,  0x10,  0xfe,  0xc5,  0x59,  0x01,  0x47,
+  0xfe,  0x8d,  0x56,  0xbe,  0x49,  0x03,  0x49,  0x21,  0x8e,  0x01,  0x15,  0x49,  0x94,  0x01,  0x47,  0xe9,
+  0x10,  0xe6,  0x10,  0x21,  0x5c,  0x61,  0x1e,  0x87,  0x0f,  0x5e,  0x01,  0xc5,  0x03,  0x0e,  0x5c,  0x12,
+  0x8e,  0xfe,  0xc3,  0x58,  0x01,  0x15,  0x05,  0x10,  0xfe,  0x1a,  0x12,  0x49,  0xee,  0x94,  0x01,  0x47,
+  0xe9,  0x10,  0xfe,  0x80,  0x4d,  0xfe,  0xc5,  0x59,  0x01,  0x47,  0x49,  0x03,  0x49,  0x21,  0x5c,  0x01,
+  0x15,  0x49,  0x94,  0x01,  0x47,  0xe9,  0x10,  0xe6,  0x10,  0x21,  0x5c,  0x61,  0x1e,  0x87,  0x0f,  0x5e,
+  0x01,  0xc5,  0x03,  0x0e,  0x5c,  0x12,  0x8e,  0xfe,  0x43,  0x58,  0x01,  0x15,  0xfe,  0x42,  0x48,  0x94,
+  0x01,  0x47,  0xfe,  0xc0,  0x5a,  0xb7,  0xfe,  0x00,  0xcd,  0xfe,  0x01,  0xcc,  0xfe,  0x4a,  0x46,  0xe4,
+  0x9a,  0x7f,  0x05,  0x10,  0xfe,  0x2e,  0x13,  0x5a,  0x5c,  0xfe,  0x4d,  0xf4,  0x1e,  0xe2,  0x0f,  0x5e,
+  0x01,  0x9f,  0xad,  0xfe,  0x40,  0x4c,  0xfe,  0xc5,  0x58,  0x01,  0x47,  0xfe,  0x00,  0x07,  0x7f,  0x05,
+  0x10,  0x87,  0x5a,  0x8e,  0xfe,  0x05,  0x57,  0xfe,  0x08,  0x10,  0xfe,  0x45,  0x58,  0x01,  0x47,  0xfe,
+  0x8d,  0x56,  0xbe,  0xfe,  0x80,  0x4c,  0xfe,  0x05,  0x17,  0x03,  0x09,  0x10,  0x75,  0x6d,  0xfe,  0x60,
+  0x01,  0xfe,  0x18,  0xdf,  0xfe,  0x19,  0xde,  0xfe,  0x24,  0x1c,  0xe3,  0x39,  0x9e,  0xfe,  0xc4,  0x16,
+  0x01,  0xfe,  0xca,  0x17,  0xd9,  0x8a,  0x39,  0x6d,  0xfe,  0x2c,  0x01,  0xfe,  0x2f,  0x19,  0x03,  0xbf,
+  0x28,  0xfe,  0xb4,  0x16,  0xfe,  0xda,  0x10,  0x09,  0x10,  0x75,  0x04,  0xfe,  0x64,  0x01,  0xfe,  0x00,
+  0xf4,  0x22,  0xfe,  0x18,  0x58,  0x04,  0xfe,  0x66,  0x01,  0xfe,  0x19,  0x58,  0x8a,  0x22,  0xfe,  0x3c,
+  0x90,  0xfe,  0x30,  0xf4,  0x06,  0xfe,  0x3c,  0x50,  0x6d,  0xfe,  0x38,  0x00,  0xfe,  0x0f,  0x79,  0xfe,
+  0x1c,  0xf7,  0x22,  0x9e,  0xfe,  0x0e,  0x17,  0xfe,  0xb6,  0x14,  0x30,  0x03,  0xbf,  0x28,  0xfe,  0xe6,
+  0x16,  0xfe,  0x9c,  0x10,  0x09,  0x10,  0x75,  0xbe,  0xfe,  0x18,  0xdf,  0xfe,  0x19,  0xdf,  0xe3,  0x31,
+  0x9e,  0xfe,  0x30,  0x17,  0xfe,  0x94,  0x14,  0x2e,  0x8a,  0x31,  0x6d,  0x1d,  0xfe,  0xaf,  0x19,  0xfe,
+  0x98,  0xe7,  0x00,  0x03,  0xbf,  0x28,  0xfe,  0x24,  0x17,  0xfe,  0x6c,  0x10,  0x09,  0x10,  0x75,  0xfe,
+  0x30,  0xbc,  0xfe,  0xb2,  0xbc,  0x8a,  0xe0,  0x6d,  0x1d,  0xfe,  0x0f,  0x79,  0xfe,  0x1c,  0xf7,  0xe0,
+  0x9e,  0xfe,  0x68,  0x17,  0xfe,  0x5c,  0x14,  0x30,  0x03,  0xbf,  0x28,  0xfe,  0x54,  0x17,  0xfe,  0x42,
+  0x10,  0xfe,  0x02,  0xf6,  0x10,  0x75,  0xfe,  0x18,  0xfe,  0x65,  0xfe,  0x19,  0xfe,  0x66,  0xd0,  0xe3,
+  0x78,  0x9e,  0xfe,  0x8e,  0x17,  0xfe,  0x36,  0x14,  0xe2,  0x8a,  0x78,  0x46,  0xfe,  0x83,  0x58,  0xfe,
+  0xaf,  0x19,  0xfe,  0x80,  0xe7,  0x10,  0xfe,  0x81,  0xe7,  0x10,  0x11,  0xfe,  0xdd,  0x00,  0x6b,  0x33,
+  0x03,  0x6b,  0x33,  0xfe,  0x12,  0x45,  0x28,  0xfe,  0x7e,  0x17,  0x17,  0x06,  0x4b,  0xfb,  0xe5,  0x02,
+  0x27,  0xfe,  0x39,  0xf0,  0xfe,  0xd2,  0x17,  0x24,  0x03,  0xfe,  0x7e,  0x18,  0x1b,  0x18,  0x85,  0x07,
+  0x0d,  0x03,  0x75,  0x04,  0xe7,  0x1b,  0x06,  0xfe,  0xef,  0x12,  0xfe,  0xe1,  0x10,  0x1c,  0x0f,  0x1e,
+  0x01,  0x15,  0x05,  0x10,  0x4e,  0x4c,  0xfe,  0x78,  0x14,  0xfe,  0x34,  0x12,  0x58,  0x89,  0x37,  0x39,
+  0xc6,  0xfe,  0xe9,  0x13,  0x1c,  0x0f,  0x3d,  0x01,  0x15,  0x05,  0x10,  0x4e,  0x4c,  0xfe,  0x56,  0x14,
+  0xb0,  0x58,  0x89,  0x37,  0x39,  0xc6,  0xfe,  0xe9,  0x13,  0x09,  0x0b,  0x03,  0xfe,  0x9c,  0xe7,  0x0b,
+  0x13,  0xfe,  0x15,  0x00,  0x97,  0xa3,  0x33,  0x01,  0xfe,  0xf8,  0x0e,  0x09,  0x06,  0x03,  0x0a,  0x4f,
+  0x39,  0x3a,  0x07,  0x3d,  0x09,  0xa1,  0x01,  0x40,  0x11,  0x48,  0x07,  0x1e,  0x09,  0x51,  0x01,  0x79,
+  0x09,  0x06,  0x03,  0xfe,  0x38,  0x90,  0xfe,  0xba,  0x90,  0x36,  0xfe,  0xa8,  0x00,  0x21,  0x7b,  0xfe,
+  0x48,  0x55,  0x30,  0xfe,  0xc9,  0x55,  0x03,  0x2a,  0xc4,  0x72,  0x16,  0xc4,  0x03,  0x0f,  0xc7,  0x01,
+  0x15,  0xed,  0x0f,  0x7e,  0x01,  0x15,  0xfe,  0x49,  0x44,  0x28,  0xfe,  0xc8,  0x18,  0x0f,  0x1e,  0x01,
+  0x15,  0x05,  0x10,  0x4e,  0x0f,  0x5e,  0x01,  0xc5,  0x0f,  0x7e,  0x01,  0x15,  0x72,  0x7f,  0x03,  0xfe,
+  0x40,  0x5e,  0xfe,  0xe2,  0x08,  0xfe,  0xc0,  0x4c,  0x2a,  0x3c,  0x05,  0x10,  0xfe,  0x52,  0x12,  0x4c,
+  0x05,  0x00,  0xfe,  0x18,  0x12,  0xfe,  0xe1,  0x18,  0xfe,  0x19,  0xf4,  0xfe,  0x7f,  0x00,  0x2e,  0xfe,
+  0xe2,  0x08,  0x72,  0x4c,  0x3e,  0x05,  0x7b,  0xa7,  0xfe,  0x82,  0x48,  0xfe,  0x01,  0x80,  0xfe,  0xd7,
+  0x10,  0xfe,  0xc4,  0x48,  0x07,  0x2d,  0x09,  0x3c,  0xfe,  0x40,  0x5f,  0x1c,  0x01,  0x40,  0x11,  0xfe,
+  0xdd,  0x00,  0xfe,  0x14,  0x46,  0x07,  0x2d,  0x09,  0x3c,  0x01,  0x40,  0x11,  0xfe,  0xdd,  0x00,  0xfe,
+  0x40,  0x4a,  0x70,  0xfe,  0x06,  0x17,  0xfe,  0x01,  0x07,  0xfe,  0x82,  0x48,  0xfe,  0x04,  0x17,  0x03,
+  0xf0,  0x18,  0x77,  0xfe,  0x50,  0x19,  0x04,  0xfe,  0x90,  0x00,  0xfe,  0x3a,  0x45,  0xfe,  0x2c,  0x10,
+  0xf0,  0xd5,  0x77,  0xfe,  0x62,  0x19,  0x04,  0xfe,  0x92,  0x00,  0xcf,  0x1d,  0xdf,  0xf0,  0xfe,  0x0b,
+  0x00,  0x77,  0xfe,  0x74,  0x19,  0x04,  0xfe,  0x94,  0x00,  0xcf,  0x22,  0xfe,  0x08,  0x10,  0x04,  0xfe,
+  0x96,  0x00,  0xcf,  0x88,  0xfe,  0x4e,  0x45,  0xd8,  0xfe,  0x0a,  0x45,  0xff,  0x04,  0x68,  0x54,  0xfe,
+  0xf1,  0x10,  0x1b,  0x8b,  0xfe,  0x08,  0x1c,  0xfe,  0x67,  0x19,  0xfe,  0x0a,  0x1c,  0xfe,  0x1a,  0xf4,
+  0xfe,  0x00,  0x04,  0xd8,  0xfe,  0x48,  0xf4,  0x18,  0x96,  0xfe,  0xa8,  0x19,  0x07,  0x18,  0x03,  0x05,
+  0xa5,  0xfe,  0x5a,  0xf0,  0xfe,  0xb8,  0x19,  0x20,  0xfe,  0x09,  0x00,  0xfe,  0x34,  0x10,  0x05,  0x1d,
+  0xfe,  0x5a,  0xf0,  0xfe,  0xc6,  0x19,  0x20,  0xd6,  0xfe,  0x26,  0x10,  0x05,  0x18,  0x85,  0x20,  0x88,
+  0xdf,  0x05,  0x0b,  0x85,  0x20,  0xae,  0xfe,  0x0e,  0x10,  0x05,  0x06,  0x85,  0x20,  0x5d,  0xce,  0xb5,
+  0x03,  0x17,  0xfe,  0x09,  0x00,  0x01,  0x2e,  0x2f,  0xfe,  0xf6,  0x19,  0x04,  0x74,  0xb7,  0x03,  0x19,
+  0xfe,  0x16,  0x1a,  0xfe,  0x14,  0xf0,  0x0c,  0x2f,  0xfe,  0x0a,  0x1a,  0x19,  0xfe,  0x16,  0x1a,  0xfe,
+  0x82,  0xf0,  0xfe,  0x0e,  0x1a,  0x03,  0xff,  0x34,  0x00,  0x00,};
+
+STATIC unsigned short _adv_asc38C0800_size =
+    sizeof(_adv_asc38C0800_buf); /* 0x14AA */
+STATIC unsigned long _adv_asc38C0800_chksum =
+    0x05297A65UL; /* Expanded checksum. */
 
 /* a_init.c */
 /*
@@ -14021,8 +15382,8 @@ unsigned long  _adv_mcode_chksum ASC_INITDATA = 0x03494981UL;
  * Additional structure information can be found in a_condor.h where
  * the structure is defined.
  */
-STATIC ADVEEP_CONFIG
-Default_EEPROM_Config ASC_INITDATA = {
+STATIC ADVEEP_3550_CONFIG
+Default_3550_EEPROM_Config ASC_INITDATA = {
     ADV_EEPROM_BIOS_ENABLE,     /* cfg_msw */
     0x0000,                     /* cfg_lsw */
     0xFFFF,                     /* disc_enable */
@@ -14038,7 +15399,7 @@ Default_EEPROM_Config ASC_INITDATA = {
     0,                          /* bios_id_lun */
     0,                          /* termination */
     0,                          /* reserved1 */
-    0xFFEF,                     /* bios_ctrl */
+    0xFFE7,                     /* bios_ctrl */
     0xFFFF,                     /* ultra_able */
     0,                          /* reserved2 */
     ASC_DEF_MAX_HOST_QNG,       /* max_host_qng */
@@ -14059,6 +15420,71 @@ Default_EEPROM_Config ASC_INITDATA = {
     0                           /* num_of_err */
 };
 
+STATIC ADVEEP_38C0800_CONFIG
+Default_38C0800_EEPROM_Config ASC_INITDATA = {
+    ADV_EEPROM_BIOS_ENABLE,     /* 00 cfg_msw */
+    0x0000,                     /* 01 cfg_lsw */
+    0xFFFF,                     /* 02 disc_enable */
+    0xFFFF,                     /* 03 wdtr_able */
+    0x4444,                     /* 04 sdtr_speed1 */
+    0xFFFF,                     /* 05 start_motor */
+    0xFFFF,                     /* 06 tagqng_able */
+    0xFFFF,                     /* 07 bios_scan */
+    0,                          /* 08 scam_tolerant */
+    7,                          /* 09 adapter_scsi_id */
+    0,                          /*    bios_boot_delay */
+    3,                          /* 10 scsi_reset_delay */
+    0,                          /*    bios_id_lun */
+    0,                          /* 11 termination_se */
+    0,                          /*    termination_lvd */
+    0xFFE7,                     /* 12 bios_ctrl */
+    0x4444,                     /* 13 sdtr_speed2 */
+    0x4444,                     /* 14 sdtr_speed3 */
+    ASC_DEF_MAX_HOST_QNG,       /* 15 max_host_qng */
+    ASC_DEF_MAX_DVC_QNG,        /*    max_dvc_qng */
+    0,                          /* 16 dvc_cntl */
+    0x4444,                     /* 17 sdtr_speed4 */
+    0,                          /* 18 serial_number_word1 */
+    0,                          /* 19 serial_number_word2 */
+    0,                          /* 20 serial_number_word3 */
+    0,                          /* 21 check_sum */
+    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, /* 22-29 oem_name[16] */
+    0,                          /* 30 dvc_err_code */
+    0,                          /* 31 adv_err_code */
+    0,                          /* 32 adv_err_addr */
+    0,                          /* 33 saved_dvc_err_code */
+    0,                          /* 34 saved_adv_err_code */
+    0,                          /* 35 saved_adv_err_addr */
+    0,                          /* 36 reserved */
+    0,                          /* 37 reserved */
+    0,                          /* 38 reserved */
+    0,                          /* 39 reserved */
+    0,                          /* 40 reserved */
+    0,                          /* 41 reserved */
+    0,                          /* 42 reserved */
+    0,                          /* 43 reserved */
+    0,                          /* 44 reserved */
+    0,                          /* 45 reserved */
+    0,                          /* 46 reserved */
+    0,                          /* 47 reserved */
+    0,                          /* 48 reserved */
+    0,                          /* 49 reserved */
+    0,                          /* 50 reserved */
+    0,                          /* 51 reserved */
+    0,                          /* 52 reserved */
+    0,                          /* 53 reserved */
+    0,                          /* 54 reserved */
+    0,                          /* 55 reserved */
+    0,                          /* 56 cisptr_lsw */
+    0,                          /* 57 cisprt_msw */
+    ADV_PCI_VENDOR_ID,          /* 58 subsysvid */
+    ADV_PCI_DEVID_38C0800_REV1, /* 59 subsysid */
+    0,                          /* 60 reserved */
+    0,                          /* 61 reserved */
+    0,                          /* 62 reserved */
+    0                           /* 63 reserved */
+};
+
 /*
  * Initialize the ADV_DVC_VAR structure.
  *
@@ -14067,8 +15493,10 @@ Default_EEPROM_Config ASC_INITDATA = {
  * For a non-fatal error return a warning code. If there are no warnings
  * then 0 is returned.
  */
-int ASC_INIT
+ASC_INITFUNC(
+STATIC int,
 AdvInitGetConfig(ADV_DVC_VAR *asc_dvc)
+)
 {
     ushort      warn_code;
     AdvPortAddr iop_base;
@@ -14119,8 +15547,8 @@ AdvInitGetConfig(ADV_DVC_VAR *asc_dvc)
     /*
      * Save the state of the PCI Configuration Command Register
      * "Parity Error Response Control" Bit. If the bit is clear (0),
-     * in AdvInitAsc3550Driver() tell the microcode to ignore DMA
-     * parity errors.
+     * in AdvInitAsc3550/38C0800Driver() tell the microcode to ignore
+     * DMA parity errors.
      */
     asc_dvc->cfg->control_flag = 0;
     if (((DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigCommandRegister)
@@ -14129,13 +15557,19 @@ AdvInitGetConfig(ADV_DVC_VAR *asc_dvc)
         asc_dvc->cfg->control_flag |= CONTROL_FLAG_IGNORE_PERR;
     }
 
-    asc_dvc->cur_host_qng = 0;
-
     asc_dvc->cfg->lib_version = (ADV_LIB_VERSION_MAJOR << 8) |
       ADV_LIB_VERSION_MINOR;
     asc_dvc->cfg->chip_version =
       AdvGetChipVersion(iop_base, asc_dvc->bus_type);
 
+    ASC_DBG2(1, "iopb_chip_id_1: %x %x\n",
+        (ushort) AdvReadByteRegister(iop_base, IOPB_CHIP_ID_1),
+        (ushort) ADV_CHIP_ID_BYTE);
+
+    ASC_DBG2(1, "iopw_chip_id_0: %x %x\n",
+        (ushort) AdvReadWordRegister(iop_base, IOPW_CHIP_ID_0),
+        (ushort) ADV_CHIP_ID_WORD);
+
     /*
      * Reset the chip to start and allow register writes.
      */
@@ -14145,37 +15579,54 @@ AdvInitGetConfig(ADV_DVC_VAR *asc_dvc)
         return ADV_ERROR;
     }
     else {
-
-        AdvResetChip(asc_dvc);
-
-        if ((status = AdvInitFromEEP(asc_dvc)) == ADV_ERROR)
+        /*
+         * The caller must set 'chip_type' to a valid setting.
+         */
+        if (asc_dvc->chip_type != ADV_CHIP_ASC3550 &&
+            asc_dvc->chip_type != ADV_CHIP_ASC38C0800 &&
+            asc_dvc->chip_type != ADV_CHIP_ASC38C1600)
         {
+            asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
             return ADV_ERROR;
         }
-        warn_code |= status;
 
         /*
-         * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
-         * Resets should be performed.
+         * Reset Chip.
          */
-        if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS)
+        AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
+            ADV_CTRL_REG_CMD_RESET);
+        DvcSleepMilliSecond(100);
+        AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
+            ADV_CTRL_REG_CMD_WR_IO_REG);
+
+        if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800)
         {
-            AdvResetSCSIBus(asc_dvc);
+            if ((status = AdvInitFrom38C0800EEP(asc_dvc)) == ADV_ERROR)
+            {
+                return ADV_ERROR;
+            }
+        } else
+        {
+            if ((status = AdvInitFrom3550EEP(asc_dvc)) == ADV_ERROR)
+            {
+                return ADV_ERROR;
+            }
         }
+        warn_code |= status;
     }
 
     return warn_code;
 }
 
 /*
- * Initialize the ASC3550.
+ * Initialize the ASC-3550.
  *
  * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
  *
  * For a non-fatal error return a warning code. If there are no warnings
  * then 0 is returned.
  */
-int ASC_INIT
+STATIC int
 AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
 {
     AdvPortAddr iop_base;
@@ -14183,12 +15634,20 @@ AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
     ulong       sum;
     int         begin_addr;
     int         end_addr;
-    int         code_sum;
+    ushort      code_sum;
     int         word;
-    int         rql_addr;                   /* RISC Queue List address */
+    int         j;
+    int         adv_asc3550_expanded_size;
+    ADV_CARR_T  *carrp;
+    ulong       contig_len;
+    long        buf_size;
+    ulong       carr_paddr;
     int         i;
     ushort      scsi_cfg1;
-    uchar       biosmem[ASC_MC_BIOSLEN];    /* BIOS RISC Memory 0x40-0x8F. */
+    uchar       tid;
+    ushort      bios_mem[ASC_MC_BIOSLEN/2]; /* BIOS RISC Memory 0x40-0x8F. */
+    ushort      wdtr_able = 0, sdtr_able, tagqng_able;
+    uchar       max_cmd[ADV_MAX_TID + 1];
 
     /* If there is already an error, don't continue. */
     if (asc_dvc->err_code != 0)
@@ -14196,6 +15655,15 @@ AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
         return ADV_ERROR;
     }
 
+    /*
+     * The caller must set 'chip_type' to ADV_CHIP_ASC3550.
+     */
+    if (asc_dvc->chip_type != ADV_CHIP_ASC3550)
+    {
+        asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
+        return ADV_ERROR;
+    }
+
     warn_code = 0;
     iop_base = asc_dvc->iop_base;
 
@@ -14207,9 +15675,36 @@ AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
      * Note: This code makes the assumption, which is currently true,
      * that a chip reset does not clear RISC LRAM.
      */
-    for (i = 0; i < ASC_MC_BIOSLEN; i++)
+    for (i = 0; i < ASC_MC_BIOSLEN/2; i++)
+    {
+        AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), bios_mem[i]);
+    }
+
+    /*
+     * Save current per TID negotiated values.
+     */
+    if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM)/2] == 0x55AA)
+    {
+        ushort  bios_version, major, minor;
+
+        bios_version = bios_mem[(ASC_MC_BIOS_VERSION - ASC_MC_BIOSMEM)/2];
+        major = (bios_version  >> 12) & 0xF;
+        minor = (bios_version  >> 8) & 0xF;
+        if (major <= 3 || (major == 3 && minor == 1))
+        {
+            /* BIOS 3.1 and earlier location of 'wdtr_able' variable. */
+            AdvReadWordLram(iop_base, 0x120, wdtr_able);
+        } else
+        {
+            AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+        }
+    }
+    AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+    AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+    for (tid = 0; tid <= ADV_MAX_TID; tid++)
     {
-        AdvReadByteLram(iop_base, ASC_MC_BIOSMEM + i, biosmem[i]);
+        AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+            max_cmd[tid]);
     }
 
     /*
@@ -14218,16 +15713,58 @@ AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
      * Write the microcode image to RISC memory starting at address 0.
      */
     AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
-    for (word = 0; word < _adv_mcode_size; word += 2)
+    /* Assume the following compressed format of the microcode buffer:
+     *
+     *  254 word (508 byte) table indexed by byte code followed
+     *  by the following byte codes:
+     *
+     *    1-Byte Code:
+     *      00: Emit word 0 in table.
+     *      01: Emit word 1 in table.
+     *      .
+     *      FD: Emit word 253 in table.
+     *
+     *    Multi-Byte Code:
+     *      FE WW WW: (3 byte code) Word to emit is the next word WW WW.
+     *      FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
+     */
+    word = 0;
+    for (i = 253 * 2; i < _adv_asc3550_size; i++)
     {
-        AdvWriteWordAutoIncLram(iop_base,
-            *((ushort *) (&_adv_mcode_buf[word])));
+        if (_adv_asc3550_buf[i] == 0xff)
+        {
+            for (j = 0; j < _adv_asc3550_buf[i + 1]; j++)
+            {
+                AdvWriteWordAutoIncLram(iop_base,
+                    *((ushort *) (&_adv_asc3550_buf[i + 2])));
+                word++;
+            }
+           i += 3;
+        } else if (_adv_asc3550_buf[i] == 0xfe)
+        {
+            AdvWriteWordAutoIncLram(iop_base,
+                *((ushort *) (&_adv_asc3550_buf[i + 1])));
+            i += 2;
+            word++;
+        } else
+        {
+            AdvWriteWordAutoIncLram(iop_base,
+                *((ushort *) &_adv_asc3550_buf[_adv_asc3550_buf[i] * 2]));
+            word++;
+        }
     }
 
     /*
-     * Clear the rest of Condor's Internal RAM (8KB).
+     * Set 'word' for later use to clear the rest of memory and save
+     * the expanded mcode size.
+     */
+    word *= 2;
+    adv_asc3550_expanded_size = word;
+
+    /*
+     * Clear the rest of ASC-3550 Internal RAM (8KB).
      */
-    for (; word < ADV_CONDOR_MEMSIZE; word += 2)
+    for (; word < ADV_3550_MEMSIZE; word += 2)
     {
         AdvWriteWordAutoIncLram(iop_base, 0);
     }
@@ -14237,12 +15774,13 @@ AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
      */
     sum = 0;
     AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
-    for (word = 0; word < _adv_mcode_size; word += 2)
+
+    for (word = 0; word < adv_asc3550_expanded_size; word += 2)
     {
         sum += AdvReadWordAutoIncLram(iop_base);
     }
 
-    if (sum != _adv_mcode_chksum)
+    if (sum != _adv_asc3550_chksum)
     {
         asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
         return ADV_ERROR;
@@ -14251,35 +15789,35 @@ AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
     /*
      * Restore the RISC memory BIOS region.
      */
-    for (i = 0; i < ASC_MC_BIOSLEN; i++)
+    for (i = 0; i < ASC_MC_BIOSLEN/2; i++)
     {
-        AdvWriteByteLram(iop_base, ASC_MC_BIOSMEM + i, biosmem[i]);
+        AdvWriteByteLram(iop_base, ASC_MC_BIOSMEM + (2 * i), bios_mem[i]);
     }
 
     /*
      * Calculate and write the microcode code checksum to the microcode
-     * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).  
+     * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
      */
     AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
     AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
     code_sum = 0;
+    AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
     for (word = begin_addr; word < end_addr; word += 2)
     {
-        code_sum += *((ushort *) (&_adv_mcode_buf[word]));
+        code_sum += AdvReadWordAutoIncLram(iop_base);
     }
     AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
 
     /*
-     * Read microcode version and date.
+     * Read and save microcode version and date.
      */
     AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE, asc_dvc->cfg->mcode_date);
     AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM, asc_dvc->cfg->mcode_version);
 
     /*
-     * Initialize microcode operating variables
+     * Set the chip type to indicate the ASC3550.
      */
-    AdvWriteWordLram(iop_base, ASC_MC_ADAPTER_SCSI_ID,
-                       asc_dvc->chip_scsi_id);
+    AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC3550);
 
     /*
      * If the PCI Configuration Command Register "Parity Error Response
@@ -14289,7 +15827,7 @@ AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
      */
     if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR)
     {
-        /* 
+        /*
          * Note: Don't remove the use of a temporary variable in
          * the following code, otherwise the Microsoft C compiler
          * will turn the following lines into a no-op.
@@ -14300,27 +15838,86 @@ AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
     }
 
     /*
-     * Set default microcode operating variables for WDTR, SDTR, and
-     * command tag queuing based on the EEPROM configuration values.
+     * For ASC-3550, setting the START_CTL_EMFU [3:2] bits sets a FIFO
+     * threshold of 128 bytes. This register is only accessible to the host.
+     */
+    AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
+        START_CTL_EMFU | READ_CMD_MRM);
+
+    /*
+     * Microcode operating variables for WDTR, SDTR, and command tag
+     * queuing will be set in AdvInquiryHandling() based on what a
+     * device reports it is capable of in Inquiry byte 7.
      *
-     * These ADV_DVC_VAR fields and the microcode variables will be
-     * changed in AdvInquiryHandling() if it is found a device is
-     * incapable of a particular feature.
+     * If SCSI Bus Resets haev been disabled, then directly set
+     * SDTR and WDTR from the EEPROM configuration. This will allow
+     * the BIOS and warm boot to work without a SCSI bus hang on
+     * the Inquiry caused by host and target mismatched DTR values.
+     * Without the SCSI Bus Reset, before an Inquiry a device can't
+     * be assumed to be in Asynchronous, Narrow mode.
      */
+    if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0)
+    {
+        AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, asc_dvc->wdtr_able);
+        AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, asc_dvc->sdtr_able);
+    }
 
     /*
-     * Set the microcode ULTRA target mask from EEPROM value. The
-     * SDTR target mask overrides the ULTRA target mask in the
-     * microcode so it is safe to set this value without determining
-     * whether the device supports SDTR.
-     * 
-     * Note: There is no way to know whether a device supports ULTRA
-     * speed without attempting a SDTR ULTRA speed negotiation with
-     * the device. The device will reject the speed if it does not
-     * support it by responding with an SDTR message containing a
-     * slower speed.
+     * Set microcode operating variables for SDTR_SPEED1, SDTR_SPEED2,
+     * SDTR_SPEED3, and SDTR_SPEED4 based on the ULTRA EEPROM per TID
+     * bitmask. These values determine the maximum SDTR speed negotiated
+     * with a device.
+     *
+     * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
+     * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
+     * without determining here whether the device supports SDTR.
+     *
+     * 4-bit speed  SDTR speed name
+     * ===========  ===============
+     * 0000b (0x0)  SDTR disabled
+     * 0001b (0x1)  5 Mhz
+     * 0010b (0x2)  10 Mhz
+     * 0011b (0x3)  20 Mhz (Ultra)
+     * 0100b (0x4)  40 Mhz (LVD/Ultra2)
+     * 0101b (0x5)  80 Mhz (LVD2/Ultra3)
+     * 0110b (0x6)  Undefined
+     * .
+     * 1111b (0xF)  Undefined
+     */
+    word = 0;
+    for (tid = 0; tid <= ADV_MAX_TID; tid++)
+    {
+        if (ADV_TID_TO_TIDMASK(tid) & asc_dvc->ultra_able)
+        {
+            /* Set Ultra speed for TID 'tid'. */
+            word |= (0x3 << (4 * (tid % 4)));
+        } else
+        {
+            /* Set Fast speed for TID 'tid'. */
+            word |= (0x2 << (4 * (tid % 4)));
+        }
+        if (tid == 3) /* Check if done with sdtr_speed1. */
+        {
+            AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, word);
+            word = 0;
+        } else if (tid == 7) /* Check if done with sdtr_speed2. */
+        {
+            AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, word);
+            word = 0;
+        } else if (tid == 11) /* Check if done with sdtr_speed3. */
+        {
+            AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, word);
+            word = 0;
+        } else if (tid == 15) /* Check if done with sdtr_speed4. */
+        {
+            AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, word);
+            /* End of loop. */
+        }
+    }
+
+    /*
+     * Set microcode operating variable for the disconnect per TID bitmask.
      */
-    AdvWriteWordLram(iop_base, ASC_MC_ULTRA_ABLE, asc_dvc->ultra_able);
     AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE, asc_dvc->cfg->disc_enable);
 
 
@@ -14332,7 +15929,7 @@ AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
      */
     AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
         PARITY_EN | SEL_TMO_LONG | OUR_ID_EN | asc_dvc->chip_scsi_id);
-  
+
     /*
      * Determine SCSI_CFG1 Microcode Default Value.
      *
@@ -14349,8 +15946,8 @@ AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
     if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 ||
         (scsi_cfg1 & CABLE_ILLEGAL_B) == 0)
     {
-        asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION;
-        return ADV_ERROR;
+            asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION;
+            return ADV_ERROR;
     }
 
     /*
@@ -14379,7 +15976,7 @@ AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
      * termination value based on a table listed in a_condor.h.
      *
      * If manual termination was specified with an EEPROM setting
-     * then 'termination' was set-up in AdvInitFromEEP() and
+     * then 'termination' was set-up in AdvInitFrom3550EEPROM() and
      * is ready to be 'ored' into SCSI_CFG1.
      */
     if (asc_dvc->cfg->termination == 0)
@@ -14431,7 +16028,21 @@ AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
      * after it is started below.
      */
     AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1,
-                       FLTR_11_TO_20NS | scsi_cfg1);
+        FLTR_11_TO_20NS | scsi_cfg1);
+
+    /*
+     * Set MEM_CFG Microcode Default Value
+     *
+     * The microcode will set the MEM_CFG register using this value
+     * after it is started below.
+     *
+     * MEM_CFG may be accessed as a word or byte, but only bits 0-7
+     * are defined.
+     *
+     * ASC-3550 has 8KB internal memory.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
+        BIOS_EN | RAM_SZ_8KB);
 
     /*
      * Set SEL_MASK Microcode Default Value
@@ -14440,49 +16051,109 @@ AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
      * after it is started below.
      */
     AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
-                        ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
+        ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
 
     /*
-     * Link all the RISC Queue Lists together in a doubly-linked
-     * NULL terminated list.
+     * Build carrier freelist.
      *
-     * Skip the NULL (0) queue which is not used.
+     * Driver must have already allocated memory and set 'carrier_buf'.
      */
-    for (i = 1, rql_addr = ASC_MC_RISC_Q_LIST_BASE + ASC_MC_RISC_Q_LIST_SIZE;
-         i < ASC_MC_RISC_Q_TOTAL_CNT;
-         i++, rql_addr += ASC_MC_RISC_Q_LIST_SIZE)
+    ADV_ASSERT(asc_dvc->carrier_buf != NULL);
+
+    carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
+    asc_dvc->carr_freelist = NULL;
+    if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf)
     {
+        buf_size = ADV_CARRIER_BUFSIZE;
+    } else
+    {
+        buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
+    }
+
+    do {
+        /*
+         * Get physical address of the carrier 'carrp'.
+         */
+        contig_len = sizeof(ADV_CARR_T);
+        carr_paddr = DvcGetPhyAddr(asc_dvc, NULL, (uchar *) carrp,
+            (long *) &contig_len, ADV_IS_CARRIER_FLAG);
+
+        buf_size -= sizeof(ADV_CARR_T);
+
+        /*
+         * If the current carrier is not physically contiguous, then
+         * maybe there was a page crossing. Try the next carrier aligned
+         * start address.
+         */
+        if (contig_len < sizeof(ADV_CARR_T))
+        {
+            carrp++;
+            continue;
+        }
+
+        carrp->carr_pa = carr_paddr;
+        carrp->carr_va = (ulong) carrp;
+
         /*
-         * Set the current RISC Queue List's RQL_FWD and RQL_BWD pointers
-         * in a one word write and set the state (RQL_STATE) to free.
+         * Insert the carrier at the beginning of the freelist.
          */
-        AdvWriteWordLram(iop_base, rql_addr, ((i + 1) + ((i - 1) << 8)));
-        AdvWriteByteLram(iop_base, rql_addr + RQL_STATE, ASC_MC_QS_FREE);
+        carrp->next_vpa = (ulong) asc_dvc->carr_freelist;
+        asc_dvc->carr_freelist = carrp;
+
+        carrp++;
     }
+    while (buf_size > 0);
 
     /*
-     * Set the Host and RISC Queue List pointers.
-     *
-     * Both sets of pointers are initialized with the same values:
-     * ASC_MC_RISC_Q_FIRST(0x01) and ASC_MC_RISC_Q_LAST (0xFF).
+     * Set-up the Host->RISC Initiator Command Queue (ICQ).
+     */
+
+    if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL)
+    {
+        asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+        return ADV_ERROR;
+    }
+    asc_dvc->carr_freelist = (ADV_CARR_T *) asc_dvc->icq_sp->next_vpa;
+
+    /*
+     * The first command issued will be placed in the stopper carrier.
+     */
+    asc_dvc->icq_sp->next_vpa = ASC_CQ_STOPPER;
+
+    /*
+     * Set RISC ICQ physical address start value.
      */
-    AdvWriteByteLram(iop_base, ASC_MC_HOST_NEXT_READY, ASC_MC_RISC_Q_FIRST);
-    AdvWriteByteLram(iop_base, ASC_MC_HOST_NEXT_DONE, ASC_MC_RISC_Q_LAST);
+    AdvWriteDWordLram(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
+
+    /*
+     * Set-up the RISC->Host Initiator Response Queue (IRQ).
+     */
+    if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL)
+    {
+        asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+        return ADV_ERROR;
+    }
+    asc_dvc->carr_freelist = (ADV_CARR_T *) asc_dvc->irq_sp->next_vpa;
 
-    AdvWriteByteLram(iop_base, ASC_MC_RISC_NEXT_READY, ASC_MC_RISC_Q_FIRST);
-    AdvWriteByteLram(iop_base, ASC_MC_RISC_NEXT_DONE, ASC_MC_RISC_Q_LAST);
+    /*
+     * The first command completed by the RISC will be placed in
+     * the stopper.
+     *
+     * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
+     * completed the RISC will set the ASC_RQ_STOPPER bit.
+     */
+    asc_dvc->irq_sp->next_vpa = ASC_CQ_STOPPER;
 
     /*
-     * Finally, set up the last RISC Queue List (255) with
-     * a NULL forward pointer.
+     * Set RISC IRQ physical address start value.
      */
-    AdvWriteWordLram(iop_base, rql_addr, (ASC_MC_NULL_Q + ((i - 1) << 8)));
-    AdvWriteByteLram(iop_base, rql_addr + RQL_STATE, ASC_MC_QS_FREE);
+    AdvWriteDWordLram(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
+    asc_dvc->carr_pending_cnt = 0;
 
     AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
-         (ADV_INTR_ENABLE_HOST_INTR | ADV_INTR_ENABLE_GLOBAL_INTR));
+        (ADV_INTR_ENABLE_HOST_INTR | ADV_INTR_ENABLE_GLOBAL_INTR));
 
-    /* 
+    /*
      * Note: Don't remove the use of a temporary variable in
      * the following code, otherwise the Microsoft C compiler
      * will turn the following lines into a no-op.
@@ -14492,28 +16163,918 @@ AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
 
     /* finally, finally, gentlemen, start your engine */
     AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
-    return warn_code;
-}
 
-/*
- * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
- * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
- * all of this is done.
- *
- * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
+    /*
+     * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
+     * Resets should be performed. The RISC has to be running
+     * to issue a SCSI Bus Reset.
+     */
+    if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS)
+    {
+        /*
+         * If the BIOS Signature is present in memory, restore the
+         * BIOS Handshake Configuration Table and do not perform
+         * a SCSI Bus Reset.
+         */
+        if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM)/2] == 0x55AA)
+        {
+            /*
+             * Restore per TID negotiated values.
+             */
+            AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+            AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+            AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+            for (tid = 0; tid <= ADV_MAX_TID; tid++)
+            {
+                AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+                    max_cmd[tid]);
+            }
+        } else
+        {
+            if (AdvResetSB(asc_dvc) != ADV_TRUE)
+            {
+                warn_code = ASC_WARN_BUSRESET_ERROR;
+            }
+        }
+    }
+
+    return warn_code;
+}
+
+/*
+ * Initialize the ASC-38C0800.
+ *
+ * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
+ *
+ * For a non-fatal error return a warning code. If there are no warnings
+ * then 0 is returned.
+ */
+STATIC int
+AdvInitAsc38C0800Driver(ADV_DVC_VAR *asc_dvc)
+{
+    AdvPortAddr iop_base;
+    ushort      warn_code;
+    ulong       sum;
+    int         begin_addr;
+    int         end_addr;
+    ushort      code_sum;
+    int         word;
+    int         j;
+    int         adv_asc38C0800_expanded_size;
+    ADV_CARR_T  *carrp;
+    ulong       contig_len;
+    long        buf_size;
+    ulong       carr_paddr;
+    int         i;
+    ushort      scsi_cfg1;
+    uchar       byte;
+    uchar       tid;
+    ushort      bios_mem[ASC_MC_BIOSLEN/2]; /* BIOS RISC Memory 0x40-0x8F. */
+    ushort      wdtr_able, sdtr_able, tagqng_able;
+    uchar       max_cmd[ADV_MAX_TID + 1];
+
+    /* If there is already an error, don't continue. */
+    if (asc_dvc->err_code != 0)
+    {
+        return ADV_ERROR;
+    }
+
+    /*
+     * The caller must set 'chip_type' to ADV_CHIP_ASC38C0800.
+     */
+    if (asc_dvc->chip_type != ADV_CHIP_ASC38C0800)
+    {
+        asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
+        return ADV_ERROR;
+    }
+
+    warn_code = 0;
+    iop_base = asc_dvc->iop_base;
+
+    /*
+     * Save the RISC memory BIOS region before writing the microcode.
+     * The BIOS may already be loaded and using its RISC LRAM region
+     * so its region must be saved and restored.
+     *
+     * Note: This code makes the assumption, which is currently true,
+     * that a chip reset does not clear RISC LRAM.
+     */
+    for (i = 0; i < ASC_MC_BIOSLEN/2; i++)
+    {
+        AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), bios_mem[i]);
+    }
+
+    /*
+     * Save current per TID negotiated values.
+     */
+    AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+    AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+    AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+    for (tid = 0; tid <= ADV_MAX_TID; tid++)
+    {
+        AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+            max_cmd[tid]);
+    }
+
+    /*
+     * RAM BIST (RAM Built-In Self Test)
+     *
+     * Address : I/O base + offset 0x38h register (byte).
+     * Function: Bit 7-6(RW) : RAM mode
+     *                          Normal Mode   : 0x00
+     *                          Pre-test Mode : 0x40
+     *                          RAM Test Mode : 0x80
+     *           Bit 5       : unused
+     *           Bit 4(RO)   : Done bit
+     *           Bit 3-0(RO) : Status
+     *                          Host Error    : 0x08
+     *                          Int_RAM Error : 0x04
+     *                          RISC Error    : 0x02
+     *                          SCSI Error    : 0x01
+     *                          No Error      : 0x00
+     *
+     * Note: RAM BIST code should be put right here, before loading the
+     * microcode and after saving the RISC memory BIOS region.
+     */
+
+    /*
+     * LRAM Pre-test
+     *
+     * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
+     * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
+     * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
+     * to NORMAL_MODE, return an error too.
+     */
+    for (i = 0; i < 2; i++)
+    {
+        AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
+        DvcSleepMilliSecond(10);  /* Wait for 10ms before reading back. */
+        byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
+        if ((byte & RAM_TEST_DONE) == 0 || (byte & 0x0F) != PRE_TEST_VALUE)
+        {
+            asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
+            return ADV_ERROR;
+        }
+
+        AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
+        DvcSleepMilliSecond(10);  /* Wait for 10ms before reading back. */
+        if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
+            != NORMAL_VALUE)
+        {
+            asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
+            return ADV_ERROR;
+        }
+    }
+
+    /*
+     * LRAM Test - It takes about 1.5 ms to run through the test.
+     *
+     * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
+     * If Done bit not set or Status not 0, save register byte, set the
+     * err_code, and return an error.
+     */
+    AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
+    DvcSleepMilliSecond(10);  /* Wait for 10ms before checking status. */
+
+    byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
+    if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0)
+    {
+        /* Get here if Done bit not set or Status not 0. */
+        asc_dvc->bist_err_code = byte;  /* for BIOS display message */
+        asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST;
+        return ADV_ERROR;
+    }
+
+    /* We need to reset back to normal mode after LRAM test passes. */
+    AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
+
+    /*
+     * Load the Microcode
+     *
+     * Write the microcode image to RISC memory starting at address 0.
+     *
+     */
+    AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
+
+    /* Assume the following compressed format of the microcode buffer:
+     *
+     *  254 word (508 byte) table indexed by byte code followed
+     *  by the following byte codes:
+     *
+     *    1-Byte Code:
+     *      00: Emit word 0 in table.
+     *      01: Emit word 1 in table.
+     *      .
+     *      FD: Emit word 253 in table.
+     *
+     *    Multi-Byte Code:
+     *      FE WW WW: (3 byte code) Word to emit is the next word WW WW.
+     *      FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
+     */
+    word = 0;
+    for (i = 253 * 2; i < _adv_asc38C0800_size; i++)
+    {
+        if (_adv_asc38C0800_buf[i] == 0xff)
+        {
+            for (j = 0; j < _adv_asc38C0800_buf[i + 1]; j++)
+            {
+                AdvWriteWordAutoIncLram(iop_base,
+                    *((ushort *) (&_adv_asc38C0800_buf[i + 2])));
+                word++;
+            }
+           i += 3;
+        } else if (_adv_asc38C0800_buf[i] == 0xfe)
+        {
+            AdvWriteWordAutoIncLram(iop_base,
+                *((ushort *) (&_adv_asc38C0800_buf[i + 1])));
+            i += 2;
+            word++;
+        } else
+        {
+            AdvWriteWordAutoIncLram(iop_base, *((ushort *)
+                &_adv_asc38C0800_buf[_adv_asc38C0800_buf[i] * 2]));
+            word++;
+        }
+    }
+
+    /*
+     * Set 'word' for later use to clear the rest of memory and save
+     * the expanded mcode size.
+     */
+    word *= 2;
+    adv_asc38C0800_expanded_size = word;
+
+    /*
+     * Clear the rest of ASC-38C0800 Internal RAM (16KB).
+     */
+    for (; word < ADV_38C0800_MEMSIZE; word += 2)
+    {
+        AdvWriteWordAutoIncLram(iop_base, 0);
+    }
+
+    /*
+     * Verify the microcode checksum.
+     */
+    sum = 0;
+    AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
+
+    for (word = 0; word < adv_asc38C0800_expanded_size; word += 2)
+    {
+        sum += AdvReadWordAutoIncLram(iop_base);
+    }
+
+    if (sum != _adv_asc38C0800_chksum)
+    {
+        asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
+        return ADV_ERROR;
+    }
+
+    /*
+     * Restore the RISC memory BIOS region.
+     */
+    for (i = 0; i < ASC_MC_BIOSLEN/2; i++)
+    {
+        AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), bios_mem[i]);
+    }
+
+    /*
+     * Calculate and write the microcode code checksum to the microcode
+     * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
+     */
+    AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
+    AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
+    code_sum = 0;
+    AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
+    for (word = begin_addr; word < end_addr; word += 2)
+    {
+        code_sum += AdvReadWordAutoIncLram(iop_base);
+    }
+    AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
+
+    /*
+     * Read microcode version and date.
+     */
+    AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE, asc_dvc->cfg->mcode_date);
+    AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM, asc_dvc->cfg->mcode_version);
+
+    /*
+     * Set the chip type to indicate the ASC38C0800.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C0800);
+
+    /*
+     * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
+     * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
+     * cable detection and then we are able to read C_DET[3:0].
+     *
+     * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
+     * Microcode Default Value' section below.
+     */
+    scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
+    AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1, scsi_cfg1 | DIS_TERM_DRV);
+
+    /*
+     * If the PCI Configuration Command Register "Parity Error Response
+     * Control" Bit was clear (0), then set the microcode variable
+     * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
+     * to ignore DMA parity errors.
+     */
+    if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR)
+    {
+        /*
+         * Note: Don't remove the use of a temporary variable in
+         * the following code, otherwise the Microsoft C compiler
+         * will turn the following lines into a no-op.
+         */
+        AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+        word |= CONTROL_FLAG_IGNORE_PERR;
+        AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+    }
+
+    /*
+     * For ASC-38C0800, set FIFO_THRESH_80B [6:4] bits and START_CTL_TH [3:2]
+     * bits for the default FIFO threshold.
+     *
+     * Note: ASC-38C0800 FIFO threshold has been changed to 256 bytes.
+     *
+     * For DMA Errata #4 set the BC_THRESH_ENB bit.
+     */
+    AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
+        BC_THRESH_ENB | FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM);
+
+    /*
+     * Microcode operating variables for WDTR, SDTR, and command tag
+     * queuing will be set in AdvInquiryHandling() based on what a
+     * device reports it is capable of in Inquiry byte 7.
+     *
+     * If SCSI Bus Resets have been disabled, then directly set
+     * SDTR and WDTR from the EEPROM configuration. This will allow
+     * the BIOS and warm boot to work without a SCSI bus hang on
+     * the Inquiry caused by host and target mismatched DTR values.
+     * Without the SCSI Bus Reset, before an Inquiry a device can't
+     * be assumed to be in Asynchronous, Narrow mode.
+     */
+    if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0)
+    {
+        AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, asc_dvc->wdtr_able);
+        AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, asc_dvc->sdtr_able);
+    }
+
+    /*
+     * Set microcode operating variables for DISC and SDTR_SPEED1,
+     * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
+     * configuration values.
+     *
+     * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
+     * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
+     * without determining here whether the device supports SDTR.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE, asc_dvc->cfg->disc_enable);
+    AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
+    AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
+    AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
+    AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
+
+    /*
+     * Set SCSI_CFG0 Microcode Default Value.
+     *
+     * The microcode will set the SCSI_CFG0 register using this value
+     * after it is started below.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
+        PARITY_EN | SEL_TMO_LONG | OUR_ID_EN | asc_dvc->chip_scsi_id);
+
+    /*
+     * Determine SCSI_CFG1 Microcode Default Value.
+     *
+     * The microcode will set the SCSI_CFG1 register using this value
+     * after it is started below.
+     */
+
+    /* Read current SCSI_CFG1 Register value. */
+    scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
+
+    /*
+     * If the internal narrow cable is reversed all of the SCSI_CTRL
+     * register signals will be set. Check for and return an error if
+     * this condition is found.
+     */
+    if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07)
+    {
+        asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
+        return ADV_ERROR;
+    }
+
+    /*
+     * All kind of combinations of devices attached to one of four connectors
+     * are acceptable except HVD device attached. For example, LVD device can
+     * be attached to SE connector while SE device attached to LVD connector.
+     * If LVD device attached to SE connector, it only runs up to Ultra speed.
+     *
+     * If an HVD device is attached to one of LVD connectors, return an error.
+     * However, there is no way to detect HVD device attached to SE connectors.
+     */
+    if (scsi_cfg1 & HVD)
+    {
+        asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
+        return ADV_ERROR;
+    }
+
+    /*
+     * If either SE or LVD automatic termination control is enabled, then
+     * set the termination value based on a table listed in a_condor.h.
+     *
+     * If manual termination was specified with an EEPROM setting then
+     * 'termination' was set-up in AdvInitFrom38C0800EEPROM() and is ready to
+     * be 'ored' into SCSI_CFG1.
+     */
+    if ((asc_dvc->cfg->termination & TERM_SE) == 0)
+    {
+        /* SE automatic termination control is enabled. */
+        switch(scsi_cfg1 & C_DET_SE)
+        {
+            /* TERM_SE_HI: on, TERM_SE_LO: on */
+            case 0x1: case 0x2: case 0x3:
+                asc_dvc->cfg->termination |= TERM_SE;
+                break;
+
+            /* TERM_SE_HI: on, TERM_SE_LO: off */
+            case 0x0:
+                asc_dvc->cfg->termination |= TERM_SE_HI;
+                break;
+        }
+    }
+
+    if ((asc_dvc->cfg->termination & TERM_LVD) == 0)
+    {
+        /* LVD automatic termination control is enabled. */
+        switch(scsi_cfg1 & C_DET_LVD)
+        {
+            /* TERM_LVD_HI: on, TERM_LVD_LO: on */
+            case 0x4: case 0x8: case 0xC:
+                asc_dvc->cfg->termination |= TERM_LVD;
+                break;
+
+            /* TERM_LVD_HI: off, TERM_LVD_LO: off */
+            case 0x0:
+                break;
+        }
+    }
+
+    /*
+     * Clear any set TERM_SE and TERM_LVD bits.
+     */
+    scsi_cfg1 &= (~TERM_SE & ~TERM_LVD);
+
+    /*
+     * Invert the TERM_SE and TERM_LVD bits and then set 'scsi_cfg1'.
+     */
+    scsi_cfg1 |= (~asc_dvc->cfg->termination & 0xF0);
+
+    /*
+     * Clear BIG_ENDIAN, DIS_TERM_DRV, Terminator Polarity and HVD/LVD/SE bits
+     * and set possibly modified termination control bits in the Microcode
+     * SCSI_CFG1 Register Value.
+     */
+    scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL & ~HVD_LVD_SE);
+
+    /*
+     * Set SCSI_CFG1 Microcode Default Value
+     *
+     * Set possibly modified termination control and reset DIS_TERM_DRV
+     * bits in the Microcode SCSI_CFG1 Register Value.
+     *
+     * The microcode will set the SCSI_CFG1 register using this value
+     * after it is started below.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
+
+    /*
+     * Set MEM_CFG Microcode Default Value
+     *
+     * The microcode will set the MEM_CFG register using this value
+     * after it is started below.
+     *
+     * MEM_CFG may be accessed as a word or byte, but only bits 0-7
+     * are defined.
+     *
+     * ASC-38C0800 has 16KB internal memory.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
+        BIOS_EN | RAM_SZ_16KB);
+
+    /*
+     * Set SEL_MASK Microcode Default Value
+     *
+     * The microcode will set the SEL_MASK register using this value
+     * after it is started below.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
+        ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
+
+    /*
+     * Build the carrier freelist.
+     *
+     * Driver must have already allocated memory and set 'carrier_buf'.
+     */
+
+    ADV_ASSERT(asc_dvc->carrier_buf != NULL);
+
+    carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
+    asc_dvc->carr_freelist = NULL;
+    if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf)
+    {
+        buf_size = ADV_CARRIER_BUFSIZE;
+    } else
+    {
+        buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
+    }
+
+    do {
+        /*
+         * Get physical address for the carrier 'carrp'.
+         */
+        contig_len = sizeof(ADV_CARR_T);
+        carr_paddr = DvcGetPhyAddr(asc_dvc, NULL, (uchar *) carrp,
+            (long *) &contig_len, ADV_IS_CARRIER_FLAG);
+
+        buf_size -= sizeof(ADV_CARR_T);
+
+        /*
+         * If the current carrier is not physically contiguous, then
+         * maybe there was a page crossing. Try the next carrier aligned
+         * start address.
+         */
+        if (contig_len < sizeof(ADV_CARR_T))
+        {
+            carrp++;
+            continue;
+        }
+
+        carrp->carr_pa = carr_paddr;
+        carrp->carr_va = (ulong) carrp;
+
+        /*
+         * Insert the carrier at the beginning of the freelist.
+         */
+        carrp->next_vpa = (ulong) asc_dvc->carr_freelist;
+        asc_dvc->carr_freelist = carrp;
+
+        carrp++;
+    }
+    while (buf_size > 0);
+
+    /*
+     * Set-up the Host->RISC Initiator Command Queue (ICQ).
+     */
+
+    if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL)
+    {
+        asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+        return ADV_ERROR;
+    }
+    asc_dvc->carr_freelist = (ADV_CARR_T *) asc_dvc->icq_sp->next_vpa;
+
+    /*
+     * The first command issued will be placed in the stopper carrier.
+     */
+    asc_dvc->icq_sp->next_vpa = ASC_CQ_STOPPER;
+
+    /*
+     * Set RISC ICQ physical address start value.
+     */
+    AdvWriteDWordLram(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
+
+    /*
+     * Set-up the RISC->Host Initiator Response Queue (IRQ).
+     */
+    if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL)
+    {
+        asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+        return ADV_ERROR;
+    }
+    asc_dvc->carr_freelist = (ADV_CARR_T *) asc_dvc->irq_sp->next_vpa;
+
+    /*
+     * The first command completed by the RISC will be placed in
+     * the stopper.
+     *
+     * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
+     * completed the RISC will set the ASC_RQ_STOPPER bit.
+     */
+    asc_dvc->irq_sp->next_vpa = ASC_CQ_STOPPER;
+
+    /*
+     * Set RISC IRQ physical address start value.
+     */
+    AdvWriteDWordLram(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
+    asc_dvc->carr_pending_cnt = 0;
+
+    AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
+        (ADV_INTR_ENABLE_HOST_INTR | ADV_INTR_ENABLE_GLOBAL_INTR));
+    /*
+     * Note: Don't remove the use of a temporary variable in
+     * the following code, otherwise the Microsoft C compiler
+     * will turn the following lines into a no-op.
+     */
+    AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
+    AdvWriteWordRegister(iop_base, IOPW_PC, word);
+
+    /* finally, finally, gentlemen, start your engine */
+    AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
+
+    /*
+     * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
+     * Resets should be performed. The RISC has to be running
+     * to issue a SCSI Bus Reset.
+     */
+    if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS)
+    {
+        /*
+         * If the BIOS Signature is present in memory, restore the
+         * BIOS Handshake Configuration Table and do not perform
+         * a SCSI Bus Reset.
+         */
+        if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM)/2] == 0x55AA)
+        {
+            /*
+             * Restore per TID negotiated values.
+             */
+            AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+            AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+            AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+            for (tid = 0; tid <= ADV_MAX_TID; tid++)
+            {
+                AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+                    max_cmd[tid]);
+            }
+        } else
+        {
+            if (AdvResetSB(asc_dvc) != ADV_TRUE)
+            {
+                warn_code = ASC_WARN_BUSRESET_ERROR;
+            }
+        }
+    }
+
+    return warn_code;
+}
+
+/*
+ * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
+ * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
+ * all of this is done.
+ *
+ * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
+ *
+ * For a non-fatal error return a warning code. If there are no warnings
+ * then 0 is returned.
+ *
+ * Note: Chip is stopped on entry.
+ */
+ASC_INITFUNC(
+STATIC int,
+AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc)
+)
+{
+    AdvPortAddr              iop_base;
+    ushort                   warn_code;
+    ADVEEP_38C0800_CONFIG    eep_config;
+    int                      i;
+    uchar                    tid, termination;
+    ushort                   sdtr_speed = 0;
+
+    iop_base = asc_dvc->iop_base;
+
+    warn_code = 0;
+
+    /*
+     * Read the board's EEPROM configuration.
+     *
+     * Set default values if a bad checksum is found.
+     */
+    if (AdvGet38C0800EEPConfig(iop_base, &eep_config) != eep_config.check_sum)
+    {
+        warn_code |= ASC_WARN_EEPROM_CHKSUM;
+
+        /*
+         * Set EEPROM default values.
+         */
+        for (i = 0; i < sizeof(ADVEEP_38C0800_CONFIG); i++)
+        {
+            *((uchar *) &eep_config + i) =
+                *((uchar *) &Default_38C0800_EEPROM_Config + i);
+        }
+
+        /*
+         * Assume the 6 byte board serial number that was read
+         * from EEPROM is correct even if the EEPROM checksum
+         * failed.
+         */
+        eep_config.serial_number_word3 =
+            AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 1);
+
+        eep_config.serial_number_word2 =
+            AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 2);
+
+        eep_config.serial_number_word1 =
+            AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 3);
+
+        AdvSet38C0800EEPConfig(iop_base, &eep_config);
+    }
+    /*
+     * Set ADV_DVC_VAR and ADV_DVC_CFG variables from the
+     * EEPROM configuration that was read.
+     *
+     * This is the mapping of EEPROM fields to Adv Library fields.
+     */
+    asc_dvc->wdtr_able = eep_config.wdtr_able;
+    asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
+    asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
+    asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
+    asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
+    asc_dvc->tagqng_able = eep_config.tagqng_able;
+    asc_dvc->cfg->disc_enable = eep_config.disc_enable;
+    asc_dvc->max_host_qng = eep_config.max_host_qng;
+    asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
+    asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
+    asc_dvc->start_motor = eep_config.start_motor;
+    asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
+    asc_dvc->bios_ctrl = eep_config.bios_ctrl;
+    asc_dvc->no_scam = eep_config.scam_tolerant;
+    asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
+    asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
+    asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
+
+    /*
+     * For every Target ID if any of its 'sdtr_speed[1234]' bits
+     * are set, then set an 'sdtr_able' bit for it.
+     */
+    asc_dvc->sdtr_able = 0;
+    for (tid = 0; tid <= ADV_MAX_TID; tid++)
+    {
+        if (tid == 0)
+        {
+            sdtr_speed = asc_dvc->sdtr_speed1;
+        } else if (tid == 4)
+        {
+            sdtr_speed = asc_dvc->sdtr_speed2;
+        } else if (tid == 8)
+        {
+            sdtr_speed = asc_dvc->sdtr_speed3;
+        } else if (tid == 12)
+        {
+            sdtr_speed = asc_dvc->sdtr_speed4;
+        }
+        if (sdtr_speed & ADV_MAX_TID)
+        {
+            asc_dvc->sdtr_able |= (1 << tid);
+        }
+        sdtr_speed >>= 4;
+    }
+
+    /*
+     * Set the host maximum queuing (max. 253, min. 16) and the per device
+     * maximum queuing (max. 63, min. 4).
+     */
+    if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG)
+    {
+        eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
+    } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG)
+    {
+        /* If the value is zero, assume it is uninitialized. */
+        if (eep_config.max_host_qng == 0)
+        {
+            eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
+        } else
+        {
+            eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
+        }
+    }
+
+    if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG)
+    {
+        eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
+    } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG)
+    {
+        /* If the value is zero, assume it is uninitialized. */
+        if (eep_config.max_dvc_qng == 0)
+        {
+            eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
+        } else
+        {
+            eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
+        }
+    }
+
+    /*
+     * If 'max_dvc_qng' is greater than 'max_host_qng', then
+     * set 'max_dvc_qng' to 'max_host_qng'.
+     */
+    if (eep_config.max_dvc_qng > eep_config.max_host_qng)
+    {
+        eep_config.max_dvc_qng = eep_config.max_host_qng;
+    }
+
+    /*
+     * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
+     * values based on possibly adjusted EEPROM values.
+     */
+    asc_dvc->max_host_qng = eep_config.max_host_qng;
+    asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
+
+    /*
+     * If the EEPROM 'termination' field is set to automatic (0), then set
+     * the ADV_DVC_CFG 'termination' field to automatic also.
+     *
+     * If the termination is specified with a non-zero 'termination'
+     * value check that a legal value is set and set the ADV_DVC_CFG
+     * 'termination' field appropriately.
+     */
+    if (eep_config.termination_se == 0)
+    {
+        termination = 0;                         /* auto termination for SE */
+    } else
+    {
+        /* Enable manual control with low off / high off. */
+        if (eep_config.termination_se == 1)
+        {
+            termination = 0;
+
+        /* Enable manual control with low off / high on. */
+        } else if (eep_config.termination_se == 2)
+        {
+            termination = TERM_SE_HI;
+
+        /* Enable manual control with low on / high on. */
+        } else if (eep_config.termination_se == 3)
+        {
+            termination = TERM_SE;
+        } else
+        {
+            /*
+             * The EEPROM 'termination_se' field contains a bad value.
+             * Use automatic termination instead.
+             */
+            termination = 0;
+            warn_code |= ASC_WARN_EEPROM_TERMINATION;
+        }
+    }
+
+    if (eep_config.termination_lvd == 0)
+    {
+        asc_dvc->cfg->termination = termination; /* auto termination for LVD */
+    } else
+    {
+        /* Enable manual control with low off / high off. */
+        if (eep_config.termination_lvd == 1)
+        {
+            asc_dvc->cfg->termination = termination;
+
+        /* Enable manual control with low off / high on. */
+        } else if (eep_config.termination_lvd == 2)
+        {
+            asc_dvc->cfg->termination = termination | TERM_LVD_HI;
+
+        /* Enable manual control with low on / high on. */
+        } else if (eep_config.termination_lvd == 3)
+        {
+            asc_dvc->cfg->termination =
+                termination | TERM_LVD;
+        } else
+        {
+            /*
+             * The EEPROM 'termination_lvd' field contains a bad value.
+             * Use automatic termination instead.
+             */
+            asc_dvc->cfg->termination = termination;
+            warn_code |= ASC_WARN_EEPROM_TERMINATION;
+        }
+    }
+
+    return warn_code;
+}
+
+/*
+ * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
+ * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
+ * all of this is done.
+ *
+ * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
  *
  * For a non-fatal error return a warning code. If there are no warnings
  * then 0 is returned.
  *
  * Note: Chip is stopped on entry.
  */
-STATIC int ASC_INIT
-AdvInitFromEEP(ADV_DVC_VAR *asc_dvc)
+ASC_INITFUNC(
+STATIC int,
+AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc)
+)
 {
     AdvPortAddr         iop_base;
     ushort              warn_code;
-    ADVEEP_CONFIG       eep_config;
+    ADVEEP_3550_CONFIG  eep_config;
     int                 i;
 
     iop_base = asc_dvc->iop_base;
@@ -14525,17 +17086,17 @@ AdvInitFromEEP(ADV_DVC_VAR *asc_dvc)
      *
      * Set default values if a bad checksum is found.
      */
-    if (AdvGetEEPConfig(iop_base, &eep_config) != eep_config.check_sum)
+    if (AdvGet3550EEPConfig(iop_base, &eep_config) != eep_config.check_sum)
     {
         warn_code |= ASC_WARN_EEPROM_CHKSUM;
 
         /*
          * Set EEPROM default values.
          */
-        for (i = 0; i < sizeof(ADVEEP_CONFIG); i++)
+        for (i = 0; i < sizeof(ADVEEP_3550_CONFIG); i++)
         {
             *((uchar *) &eep_config + i) =
-                *((uchar *) &Default_EEPROM_Config + i);
+                *((uchar *) &Default_3550_EEPROM_Config + i);
         }
 
         /*
@@ -14545,15 +17106,17 @@ AdvInitFromEEP(ADV_DVC_VAR *asc_dvc)
          */
         eep_config.serial_number_word3 =
             AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 1);
+
         eep_config.serial_number_word2 =
             AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 2);
+
         eep_config.serial_number_word1 =
             AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 3);
-        AdvSetEEPConfig(iop_base, &eep_config);
-    }
 
+        AdvSet3550EEPConfig(iop_base, &eep_config);
+    }
     /*
-     * Set ADV_DVC_VAR and ADV_DVC_CFG variables from the
+     * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
      * EEPROM configuration that was read.
      *
      * This is the mapping of EEPROM fields to Adv Library fields.
@@ -14568,7 +17131,6 @@ AdvInitFromEEP(ADV_DVC_VAR *asc_dvc)
     asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
     asc_dvc->start_motor = eep_config.start_motor;
     asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
-    asc_dvc->cfg->bios_boot_wait = eep_config.bios_boot_delay;
     asc_dvc->bios_ctrl = eep_config.bios_ctrl;
     asc_dvc->no_scam = eep_config.scam_tolerant;
     asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
@@ -14619,7 +17181,7 @@ AdvInitFromEEP(ADV_DVC_VAR *asc_dvc)
     }
 
     /*
-     * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_CFG 'max_dvc_qng'
+     * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
      * values based on possibly adjusted EEPROM values.
      */
     asc_dvc->max_host_qng = eep_config.max_host_qng;
@@ -14672,8 +17234,48 @@ AdvInitFromEEP(ADV_DVC_VAR *asc_dvc)
  *
  * Return a checksum based on the EEPROM configuration read.
  */
-STATIC ushort ASC_INIT
-AdvGetEEPConfig(AdvPortAddr iop_base, ADVEEP_CONFIG *cfg_buf)
+ASC_INITFUNC(
+STATIC ushort,
+AdvGet38C0800EEPConfig(AdvPortAddr iop_base,
+                       ADVEEP_38C0800_CONFIG *cfg_buf)
+)
+{
+    ushort              wval, chksum;
+    ushort              *wbuf;
+    int                 eep_addr;
+
+    wbuf = (ushort *) cfg_buf;
+    chksum = 0;
+
+    for (eep_addr = ASC_EEP_DVC_CFG_BEGIN;
+         eep_addr < ASC_EEP_DVC_CFG_END;
+         eep_addr++, wbuf++)
+    {
+        wval = AdvReadEEPWord(iop_base, eep_addr);
+        chksum += wval;
+        *wbuf = wval;
+    }
+    *wbuf = AdvReadEEPWord(iop_base, eep_addr);
+    wbuf++;
+    for (eep_addr = ASC_EEP_DVC_CTL_BEGIN;
+         eep_addr < ASC_EEP_MAX_WORD_ADDR;
+         eep_addr++, wbuf++)
+    {
+        *wbuf = AdvReadEEPWord(iop_base, eep_addr);
+    }
+    return chksum;
+}
+
+
+/*
+ * Read EEPROM configuration into the specified buffer.
+ *
+ * Return a checksum based on the EEPROM configuration read.
+ */
+ASC_INITFUNC(
+STATIC ushort,
+AdvGet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
+)
 {
     ushort              wval, chksum;
     ushort              *wbuf;
@@ -14704,8 +17306,10 @@ AdvGetEEPConfig(AdvPortAddr iop_base, ADVEEP_CONFIG *cfg_buf)
 /*
  * Read the EEPROM from specified location
  */
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
 AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr)
+)
 {
     AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
         ASC_EEP_CMD_READ | eep_word_addr);
@@ -14716,8 +17320,10 @@ AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr)
 /*
  * Wait for EEPROM command to complete
  */
-STATIC void ASC_INIT
+ASC_INITFUNC(
+STATIC void,
 AdvWaitEEPCmd(AdvPortAddr iop_base)
+)
 {
     int eep_delay_ms;
 
@@ -14739,11 +17345,63 @@ AdvWaitEEPCmd(AdvPortAddr iop_base)
 /*
  * Write the EEPROM from 'cfg_buf'.
  */
-STATIC void ASC_INIT
-AdvSetEEPConfig(AdvPortAddr iop_base, ADVEEP_CONFIG *cfg_buf)
+void
+AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
+{
+    ushort *wbuf;
+    ushort addr, chksum;
+
+    wbuf = (ushort *) cfg_buf;
+    chksum = 0;
+
+    AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
+    AdvWaitEEPCmd(iop_base);
+
+    /*
+     * Write EEPROM from word 0 to word 20
+     */
+    for (addr = ASC_EEP_DVC_CFG_BEGIN;
+         addr < ASC_EEP_DVC_CFG_END; addr++, wbuf++)
+    {
+        chksum += *wbuf;
+        AdvWriteWordRegister(iop_base, IOPW_EE_DATA, *wbuf);
+        AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
+        AdvWaitEEPCmd(iop_base);
+        DvcSleepMilliSecond(ASC_EEP_DELAY_MS);
+    }
+
+    /*
+     * Write EEPROM checksum at word 21
+     */
+    AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
+    AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
+    AdvWaitEEPCmd(iop_base);
+    wbuf++;        /* skip over check_sum */
+
+    /*
+     * Write EEPROM OEM name at words 22 to 29
+     */
+    for (addr = ASC_EEP_DVC_CTL_BEGIN;
+         addr < ASC_EEP_MAX_WORD_ADDR; addr++, wbuf++)
+    {
+        AdvWriteWordRegister(iop_base, IOPW_EE_DATA, *wbuf);
+        AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
+        AdvWaitEEPCmd(iop_base);
+    }
+    AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
+    AdvWaitEEPCmd(iop_base);
+    return;
+}
+
+/*
+ * Write the EEPROM from 'cfg_buf'.
+ */
+void
+AdvSet38C0800EEPConfig(AdvPortAddr iop_base,
+                       ADVEEP_38C0800_CONFIG *cfg_buf)
 {
-    ushort       *wbuf;
-    ushort       addr, chksum;
+    ushort *wbuf;
+    ushort addr, chksum;
 
     wbuf = (ushort *) cfg_buf;
     chksum = 0;
@@ -14752,7 +17410,7 @@ AdvSetEEPConfig(AdvPortAddr iop_base, ADVEEP_CONFIG *cfg_buf)
     AdvWaitEEPCmd(iop_base);
 
     /*
-     * Write EEPROM from word 0 to word 15
+     * Write EEPROM from word 0 to word 20
      */
     for (addr = ASC_EEP_DVC_CFG_BEGIN;
          addr < ASC_EEP_DVC_CFG_END; addr++, wbuf++)
@@ -14765,7 +17423,7 @@ AdvSetEEPConfig(AdvPortAddr iop_base, ADVEEP_CONFIG *cfg_buf)
     }
 
     /*
-     * Write EEPROM checksum at word 18
+     * Write EEPROM checksum at word 21
      */
     AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
     AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
@@ -14773,7 +17431,7 @@ AdvSetEEPConfig(AdvPortAddr iop_base, ADVEEP_CONFIG *cfg_buf)
     wbuf++;        /* skip over check_sum */
 
     /*
-     * Write EEPROM OEM name at words 19 to 26 
+     * Write EEPROM OEM name at words 22 to 29
      */
     for (addr = ASC_EEP_DVC_CTL_BEGIN;
          addr < ASC_EEP_MAX_WORD_ADDR; addr++, wbuf++)
@@ -14787,138 +17445,261 @@ AdvSetEEPConfig(AdvPortAddr iop_base, ADVEEP_CONFIG *cfg_buf)
     return;
 }
 
+/* a_advlib.c */
 /*
- * This function resets the chip and SCSI bus
+ * AdvExeScsiQueue() - Send a request to the RISC microcode program.
  *
- * It is up to the caller to add a delay to let the bus settle after
- * calling this function.
+ *   Allocate a carrier structure, point the carrier to the ADV_SCSI_REQ_Q,
+ *   add the carrier to the ICQ (Initiator Command Queue), and tickle the
+ *   RISC to notify it a new command is ready to be executed.
  *
- * The SCSI_CFG0, SCSI_CFG1, and MEM_CFG registers are set-up in
- * AdvInitAsc3550Driver(). Here when doing a write to one of these
- * registers read first and then write.
+ * If 'done_status' is not set to QD_DO_RETRY, then 'error_retry' will be
+ * set to SCSI_MAX_RETRY.
  *
- * Note: A SCSI Bus Reset can not be done until after the EEPROM
- * configuration is read to determine whether SCSI Bus Resets
- * should be performed.
+ * Return:
+ *      ADV_SUCCESS(1) - The request was successfully queued.
+ *      ADV_BUSY(0) -    Resource unavailable; Retry again after pending
+ *                       request completes.
+ *      ADV_ERROR(-1) -  Invalid ADV_SCSI_REQ_Q request structure
+ *                       host IC error.
  */
-STATIC void ASC_INIT
-AdvResetChip(ADV_DVC_VAR *asc_dvc)
+STATIC int
+AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc,
+                ADV_SCSI_REQ_Q *scsiq)
 {
-    AdvPortAddr    iop_base;
-    ushort         word;
-    uchar          byte;
+    int                    last_int_level;
+    AdvPortAddr            iop_base;
+    long                   req_size;
+    ulong                  req_paddr;
+    ADV_CARR_T             *new_carrp;
+
+    ADV_ASSERT(scsiq != NULL); /* 'scsiq' should never be NULL. */
+
+    /*
+     * The ADV_SCSI_REQ_Q 'target_id' field should never exceed ADV_MAX_TID.
+     */
+    if (scsiq->target_id > ADV_MAX_TID)
+    {
+        scsiq->host_status = QHSTA_M_INVALID_DEVICE;
+        scsiq->done_status = QD_WITH_ERROR;
+        return ADV_ERROR;
+    }
 
     iop_base = asc_dvc->iop_base;
 
+    last_int_level = DvcEnterCritical();
+
     /*
-     * Reset Chip.
+     * Allocate a carrier ensuring at least one carrier always
+     * remains on the freelist and initialize fields.
      */
-    AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_RESET);
-    DvcSleepMilliSecond(100);
-    AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_WR_IO_REG);
+    if ((new_carrp = asc_dvc->carr_freelist) == NULL)
+    {
+       return ADV_BUSY;
+    }
+    asc_dvc->carr_freelist = (ADV_CARR_T *) new_carrp->next_vpa;
+    asc_dvc->carr_pending_cnt++;
 
     /*
-     * Initialize Chip registers.
-     * 
-     * Note: Don't remove the use of a temporary variable in the following
-     * code, otherwise the Microsoft C compiler will turn the following lines
-     * into a no-op.
+     * Set the carrier to be a stopper by setting 'next_vpa'
+     * to the stopper value. The current stopper will be changed
+     * below to point to the new stopper.
+     */
+    new_carrp->next_vpa = ASC_CQ_STOPPER;
+
+    /*
+     * Clear the ADV_SCSI_REQ_Q done flag.
      */
-    byte = AdvReadByteRegister(iop_base, IOPB_MEM_CFG);
-    byte |= RAM_SZ_8KB;
-    AdvWriteByteRegister(iop_base, IOPB_MEM_CFG, byte);
+    scsiq->a_flag &= ~ADV_SCSIQ_DONE;
+
+    req_size = sizeof(ADV_SCSI_REQ_Q);
+    req_paddr = DvcGetPhyAddr(asc_dvc, scsiq, (uchar *) scsiq,
+        (long *) &req_size, ADV_IS_SCSIQ_FLAG);
+
+    ADV_ASSERT(ADV_DWALIGN(req_paddr) == req_paddr);
+    ADV_ASSERT(req_size >= sizeof(ADV_SCSI_REQ_Q));
+
+    /* Save virtual and physical address of ADV_SCSI_REQ_Q and Carrier. */
+    scsiq->scsiq_ptr = (ADV_SCSI_REQ_Q *) scsiq;
+    scsiq->scsiq_rptr = req_paddr;
+
+    /* XXX - Could have the RISC set these values. */
+    scsiq->carr_va = (ulong) asc_dvc->icq_sp;
+    scsiq->carr_pa = asc_dvc->icq_sp->carr_pa;
 
-    word = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
-    word &= ~BIG_ENDIAN;
-    AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1, word);
+   /*
+    * Use the current stopper to send the ADV_SCSI_REQ_Q command to
+    * the microcode. The newly allocated stopper will become the new
+    * stopper.
+    */
+    asc_dvc->icq_sp->areq_vpa = (ulong) req_paddr;
 
     /*
-     * Setting the START_CTL_EMFU 3:2 bits sets a FIFO threshold
-     * of 128 bytes. This register is only accessible to the host.
+     * Set the 'next_vpa' pointer for the old stopper to be the
+     * physical address of the new stopper. The RISC can only
+     * follow physical addresses.
      */
-    AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
-        START_CTL_EMFU | READ_CMD_MRM);
-}
+    asc_dvc->icq_sp->next_vpa = new_carrp->carr_pa;
 
-/* a_advlib.c */
-/*
- * Description:
- *      Send a SCSI request to the ASC3550 chip
- *
- * If there is no SG list for the request, set 'sg_entry_cnt' to 0.
- *
- * If 'sg_real_addr' is non-zero on entry, AscGetSGList() will not be
- * called. It is assumed the caller has already initialized 'sg_real_addr'.
- *
- * Return:
- *      ADV_SUCCESS(1) - the request is in the mailbox
- *      ADV_BUSY(0) - total request count > 253, try later
- *      ADV_ERROR(-1) - invalid scsi request Q
- */
-STATIC int
-AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc,
-                ADV_SCSI_REQ_Q *scsiq)
-{
-    if (scsiq == (ADV_SCSI_REQ_Q *) 0L)
+    /*
+     * Set the host adapter stopper pointer to point to the new carrier.
+     */
+    asc_dvc->icq_sp = new_carrp;
+
+    /*
+     * Tickle the RISC to tell it to read its Command Queue Head pointer.
+     */
+    AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A);
+    if (asc_dvc->chip_type == ADV_CHIP_ASC3550)
     {
-        /* 'scsiq' should never be NULL. */
-        ADV_ASSERT(0);
-        return ADV_ERROR;
+        /*
+         * Clear the tickle value. In the ASC-3550 the RISC flag
+         * command 'clr_tickle_a' does not work unless the host
+         * value is cleared.
+         */
+        AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP);
     }
 
-    return AdvSendScsiCmd(asc_dvc, scsiq);
+    DvcLeaveCritical(last_int_level);
+
+    return ADV_SUCCESS;
 }
 
 /*
  * Reset SCSI Bus and purge all outstanding requests.
  *
  * Return Value:
- *      ADV_TRUE(1) - All requests are purged and SCSI Bus is reset.
- *
- * Note: Should always return ADV_TRUE.
+ *      ADV_TRUE(1) -   All requests are purged and SCSI Bus is reset.
+ *      ADV_FALSE(0) -  Microcode command failed.
+ *      ADV_ERROR(-1) - Microcode command timed-out. Microcode or IC
+ *                      may be hung which requires driver recovery.
  */
 STATIC int
 AdvResetSB(ADV_DVC_VAR *asc_dvc)
 {
     int         status;
 
-    status = AdvSendIdleCmd(asc_dvc, (ushort) IDLE_CMD_SCSI_RESET, 0L, 0);
+    /*
+     * Send the SCSI Bus Reset idle start idle command which asserts
+     * the SCSI Bus Reset signal.
+     */
+    status = AdvSendIdleCmd(asc_dvc, (ushort) IDLE_CMD_SCSI_RESET_START, 0L);
+    if (status != ADV_TRUE)
+    {
+        return status;
+    }
+
+    /*
+     * Delay for the specified SCSI Bus Reset hold time.
+     *
+     * The hold time delay is done on the host because the RISC has no
+     * microsecond accurate timer.
+     */
+    DvcDelayMicroSecond(asc_dvc, (ushort) ASC_SCSI_RESET_HOLD_TIME_US);
+
+    /*
+     * Send the SCSI Bus Reset end idle command which de-asserts
+     * the SCSI Bus Reset signal and purges any pending requests.
+     */
+    status = AdvSendIdleCmd(asc_dvc, (ushort) IDLE_CMD_SCSI_RESET_END, 0L);
+    if (status != ADV_TRUE)
+    {
+        return status;
+    }
 
-    AdvResetSCSIBus(asc_dvc);
+    DvcSleepMilliSecond((ulong) asc_dvc->scsi_reset_wait * 1000);
 
     return status;
 }
 
 /*
- * Reset SCSI Bus and delay.
+ * Reset chip and SCSI Bus.
+ *
+ * Return Value:
+ *      ADV_TRUE(1) -   Chip re-initialization and SCSI Bus Reset successful.
+ *      ADV_FALSE(0) -  Chip re-initialization and SCSI Bus Reset failure.
  */
-STATIC void
-AdvResetSCSIBus(ADV_DVC_VAR *asc_dvc)
+STATIC int
+AdvResetChipAndSB(ADV_DVC_VAR *asc_dvc)
 {
-    AdvPortAddr    iop_base;
-    ushort         scsi_ctrl;
+    int         status;
+    ushort      wdtr_able, sdtr_able, tagqng_able;
+    uchar       tid, max_cmd[ADV_MAX_TID + 1];
+    AdvPortAddr iop_base;
+    ushort      bios_sig;
 
     iop_base = asc_dvc->iop_base;
 
     /*
-     * The microcode currently sets the SCSI Bus Reset signal while
-     * handling the AscSendIdleCmd() IDLE_CMD_SCSI_RESET command above.
-     * But the SCSI Bus Reset Hold Time in the microcode is not deterministic
-     * (it may in fact be for less than the SCSI Spec. minimum of 25 us).
-     * Therefore on return the Adv Library sets the SCSI Bus Reset signal
-     * for ASC_SCSI_RESET_HOLD_TIME_US, which is defined to be greater
-     * than 25 us.
+     * Save current per TID negotiated values.
      */
-    scsi_ctrl = AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL);
-    AdvWriteWordRegister(iop_base, IOPW_SCSI_CTRL,
-        scsi_ctrl | ADV_SCSI_CTRL_RSTOUT);
-    DvcDelayMicroSecond(asc_dvc, (ushort) ASC_SCSI_RESET_HOLD_TIME_US);
-    AdvWriteWordRegister(iop_base, IOPW_SCSI_CTRL,
-        scsi_ctrl & ~ADV_SCSI_CTRL_RSTOUT);
+    AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+    AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+    AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+    for (tid = 0; tid <= ADV_MAX_TID; tid++)
+    {
+        AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+            max_cmd[tid]);
+    }
 
-    DvcSleepMilliSecond((ulong) asc_dvc->scsi_reset_wait * 1000);
-}
+    /*
+     * Force the AdvInitAsc3550/38C0800Driver() function to
+     * perform a SCSI Bus Reset by clearing the BIOS signature word.
+     * The initialization functions assumes a SCSI Bus Reset is not
+     * needed if the BIOS signature word is present.
+     */
+    AdvReadWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
+    AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, 0);
 
+    /*
+     * Stop chip and reset it.
+     */
+    AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_STOP);
+    AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_RESET);
+    DvcSleepMilliSecond(100);
+    AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_WR_IO_REG);
+
+    /*
+     * Reset Adv Library error code, if any, and try
+     * re-initializing the chip.
+     */
+    asc_dvc->err_code = 0;
+    if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800)
+    {
+        status = AdvInitAsc38C0800Driver(asc_dvc);
+    } else
+    {
+        status = AdvInitAsc3550Driver(asc_dvc);
+    }
+
+    /* Translate initialization return value to status value. */
+    if (status == 0)
+    {
+        status = ADV_TRUE;
+    } else
+    {
+        status = ADV_FALSE;
+    }
+
+    /*
+     * Restore the BIOS signature word.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
+
+    /*
+     * Restore per TID negotiated values.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+    AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+    AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+    for (tid = 0; tid <= ADV_MAX_TID; tid++)
+    {
+        AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+            max_cmd[tid]);
+    }
+
+    return status;
+}
 
 /*
  * Adv Library Interrupt Service Routine
@@ -14944,79 +17725,76 @@ AdvISR(ADV_DVC_VAR *asc_dvc)
 {
     AdvPortAddr                 iop_base;
     uchar                       int_stat;
-    ushort                      next_done_loc, target_bit;
-    int                         completed_q;
+    ushort                      target_bit;
+    ADV_CARR_T                  *free_carrp;
+    ulong                       irq_next_vpa;
     int                         flags;
     ADV_SCSI_REQ_Q              *scsiq;
-    ASC_REQ_SENSE               *sense_data;
-    int                         ret;
 
     flags = DvcEnterCritical();
-    iop_base = asc_dvc->iop_base;
 
-    if (AdvIsIntPending(iop_base))
-    {
-        ret = ADV_TRUE;
-    } else
-    {
-        ret = ADV_FALSE;
-    }
+    iop_base = asc_dvc->iop_base;
 
     /* Reading the register clears the interrupt. */
     int_stat = AdvReadByteRegister(iop_base, IOPB_INTR_STATUS_REG);
 
-    if (int_stat & ADV_INTR_STATUS_INTRB)
+    if ((int_stat & (ADV_INTR_STATUS_INTRA | ADV_INTR_STATUS_INTRB |
+         ADV_INTR_STATUS_INTRC)) == 0)
     {
-        asc_dvc->idle_cmd_done = ADV_TRUE;
+        return ADV_FALSE;
     }
 
     /*
-     * Notify the driver of a hardware detected SCSI Bus Reset.
+     * Notify the driver of an asynchronous microcode condition by
+     * calling the ADV_DVC_VAR.async_callback function. The function
+     * is passed the microcode ASC_MC_INTRB_CODE byte value.
      */
-    if (int_stat & ADV_INTR_STATUS_INTRC)
+    if (int_stat & ADV_INTR_STATUS_INTRB)
     {
-        if (asc_dvc->sbreset_callback != 0)
+        uchar intrb_code;
+
+        AdvReadByteLram(iop_base, ASC_MC_INTRB_CODE, intrb_code);
+        if (intrb_code == ADV_ASYNC_CARRIER_READY_FAILURE &&
+            asc_dvc->carr_pending_cnt != 0)
+        {
+            AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A);
+            if (asc_dvc->chip_type == ADV_CHIP_ASC3550)
+            {
+                AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP);
+            }
+        }
+
+        if (asc_dvc->async_callback != 0)
         {
-            (*(ADV_SBRESET_CALLBACK) asc_dvc->sbreset_callback)(asc_dvc);
+            (*asc_dvc->async_callback)(asc_dvc, intrb_code);
         }
     }
 
     /*
-     * ASC_MC_HOST_NEXT_DONE (0x129) is actually the last completed RISC
-     * Queue List request. Its forward pointer (RQL_FWD) points to the
-     * current completed RISC Queue List request.
+     * Check if the IRQ stopper carrier contains a completed request.
      */
-    AdvReadByteLram(iop_base, ASC_MC_HOST_NEXT_DONE, next_done_loc);
-    next_done_loc = ASC_MC_RISC_Q_LIST_BASE +
-        (next_done_loc * ASC_MC_RISC_Q_LIST_SIZE) + RQL_FWD;
-
-    AdvReadByteLram(iop_base, next_done_loc, completed_q);
-
-    /* Loop until all completed Q's are processed. */
-    while (completed_q != ASC_MC_NULL_Q)
+    while (((irq_next_vpa = asc_dvc->irq_sp->next_vpa) & ASC_RQ_DONE) != 0)
     {
-        AdvWriteByteLram(iop_base, ASC_MC_HOST_NEXT_DONE, completed_q);
-
-        next_done_loc = ASC_MC_RISC_Q_LIST_BASE +
-          (completed_q * ASC_MC_RISC_Q_LIST_SIZE);
+        /*
+         * Get a pointer to the newly completed ADV_SCSI_REQ_Q structure.
+         * The RISC will have set 'areq_vpa' to a virtual address.
+         */
+        scsiq = (ADV_SCSI_REQ_Q *) asc_dvc->irq_sp->areq_vpa;
 
         /*
-         * Read the ADV_SCSI_REQ_Q virtual address pointer from
-         * the RISC list entry. The microcode has changed the
-         * ADV_SCSI_REQ_Q physical address to its virtual address.
-         *
-         * Refer to comments at the end of AdvSendScsiCmd() for
-         * more information on the RISC list structure.
+         * Advance the stopper pointer to the next carrier
+         * ignoring the lower four bits. Free the previous
+         * stopper carrier.
          */
-        {
-            ushort lsw, msw;
-            AdvReadWordLram(iop_base, next_done_loc + RQL_PHYADDR, lsw);
-            AdvReadWordLram(iop_base, next_done_loc + RQL_PHYADDR + 2, msw);
+        free_carrp = asc_dvc->irq_sp;
+        asc_dvc->irq_sp = ASC_GET_CARRP(irq_next_vpa);
+
+        free_carrp->next_vpa = (ulong) asc_dvc->carr_freelist;
+        asc_dvc->carr_freelist = (ADV_CARR_T *) free_carrp;
+        asc_dvc->carr_pending_cnt--;
 
-            scsiq = (ADV_SCSI_REQ_Q *) (((ulong) msw << 16) | lsw);
-        }
-        ADV_ASSERT(scsiq != NULL);
 
+        ADV_ASSERT(scsiq != NULL);
         target_bit = ADV_TID_TO_TIDMASK(scsiq->target_id);
 
         /*
@@ -15028,14 +17806,9 @@ AdvISR(ADV_DVC_VAR *asc_dvc)
          * Check Condition handling
          */
         if ((scsiq->done_status == QD_WITH_ERROR) &&
-            (scsiq->scsi_status == SS_CHK_CONDITION) &&
-            (sense_data = (ASC_REQ_SENSE *) scsiq->vsense_addr) != 0 &&
-            (scsiq->orig_sense_len - scsiq->sense_len) >= ASC_MIN_SENSE_LEN)
+            (scsiq->scsi_status == SS_CHK_CONDITION)
+            )
         {
-            /*
-             * Command returned with a check condition and valid
-             * sense data.
-             */
         }
         /*
          * If the command that completed was a SCSI INQUIRY and
@@ -15043,27 +17816,18 @@ AdvISR(ADV_DVC_VAR *asc_dvc)
          * command information for the device.
          */
         else if (scsiq->done_status == QD_NO_ERROR &&
-                   scsiq->cdb[0] == SCSICMD_Inquiry &&
-                   scsiq->target_lun == 0)
+                 scsiq->cdb[0] == SCSICMD_Inquiry &&
+                 scsiq->target_lun == 0)
         {
             AdvInquiryHandling(asc_dvc, scsiq);
         }
 
-        
-        /* Change the RISC Queue List state to free. */
-        AdvWriteByteLram(iop_base, next_done_loc + RQL_STATE, ASC_MC_QS_FREE);
-
-        /* Get the RISC Queue List forward pointer. */
-        AdvReadByteLram(iop_base, next_done_loc + RQL_FWD, completed_q);
-
         /*
          * Notify the driver of the completed request by passing
          * the ADV_SCSI_REQ_Q pointer to its callback function.
          */
-        ADV_ASSERT(asc_dvc->cur_host_qng > 0);
-        asc_dvc->cur_host_qng--;
         scsiq->a_flag |= ADV_SCSIQ_DONE;
-        (*(ADV_ISR_CALLBACK) asc_dvc->isr_callback)(asc_dvc, scsiq);
+        (*asc_dvc->isr_callback)(asc_dvc, scsiq);
         /*
          * Note: After the driver callback function is called, 'scsiq'
          * can no longer be referenced.
@@ -15083,231 +17847,107 @@ AdvISR(ADV_DVC_VAR *asc_dvc)
         (void) DvcEnterCritical();
     }
     DvcLeaveCritical(flags);
-    return ret;
+    return ADV_TRUE;
 }
 
 /*
  * Send an idle command to the chip and wait for completion.
  *
- * Interrupts do not have to be enabled on entry.
+ * Command completion is polled for once per microsecond.
+ *
+ * The function can be called from anywhere including an interrupt handler.
+ * But the function is not re-entrant, so it uses the DvcEnter/LeaveCritical()
+ * functions to prevent reentrancy.
  *
  * Return Values:
  *   ADV_TRUE - command completed successfully
  *   ADV_FALSE - command failed
+ *   ADV_ERROR - command timed out
  */
 STATIC int
 AdvSendIdleCmd(ADV_DVC_VAR *asc_dvc,
                ushort idle_cmd,
-               ulong idle_cmd_parameter,
-               int flags)
+               ulong idle_cmd_parameter)
 {
     int         last_int_level;
-    ulong       i;
+    int         result;
+    ulong       i, j;
     AdvPortAddr iop_base;
-    int         ret;
-
-    asc_dvc->idle_cmd_done = 0;
 
     last_int_level = DvcEnterCritical();
+
     iop_base = asc_dvc->iop_base;
 
+    /*
+     * Clear the idle command status which is set by the microcode
+     * to a non-zero value to indicate when the command is completed.
+     * The non-zero result is one of the IDLE_CMD_STATUS_* values
+     * defined in a_advlib.h.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS, (ushort) 0);
+
     /*
      * Write the idle command value after the idle command parameter
      * has been written to avoid a race condition. If the order is not
      * followed, the microcode may process the idle command before the
      * parameters have been written to LRAM.
      */
-    AdvWriteDWordLram(iop_base, ASC_MC_IDLE_PARA_STAT, idle_cmd_parameter);
+    AdvWriteDWordLram(iop_base, ASC_MC_IDLE_CMD_PARAMETER,
+        idle_cmd_parameter);
     AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD, idle_cmd);
-    DvcLeaveCritical(last_int_level);
 
     /*
-     * If the 'flags' argument contains the ADV_NOWAIT flag, then
-     * return with success.
+     * Tickle the RISC to tell it to process the idle command.
      */
-    if (flags & ADV_NOWAIT)
+    AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_B);
+    if (asc_dvc->chip_type == ADV_CHIP_ASC3550)
     {
-        return ADV_TRUE;
-    }
-
-    for (i = 0; i < SCSI_WAIT_10_SEC * SCSI_MS_PER_SEC; i++)
-    {
-        /*
-         * 'idle_cmd_done' is set by AdvISR().
-         */
-        if (asc_dvc->idle_cmd_done)
-        {
-            break;
-        }
-        DvcSleepMilliSecond(1);
-
         /*
-         * If interrupts were disabled on entry to AdvSendIdleCmd(),
-         * then they will still be disabled here. Call AdvISR() to
-         * check for the idle command completion.
+         * Clear the tickle value. In the ASC-3550 the RISC flag
+         * command 'clr_tickle_b' does not work unless the host
+         * value is cleared.
          */
-        (void) AdvISR(asc_dvc);
-    }
-
-    last_int_level = DvcEnterCritical();
-
-    if (asc_dvc->idle_cmd_done == ADV_FALSE)
-    {
-        ADV_ASSERT(0); /* The idle command should never timeout. */
-        return ADV_FALSE;
-    } else
-    {
-        AdvReadWordLram(iop_base, ASC_MC_IDLE_PARA_STAT, ret);
-        return ret;
-    }
-}
-
-/*
- * Send the SCSI request block to the adapter
- *
- * Each of the 255 Adv Library/Microcode RISC Lists or mailboxes has the
- * following structure:
- *
- * 0: RQL_FWD - RISC list forward pointer (1 byte)
- * 1: RQL_BWD - RISC list backward pointer (1 byte)
- * 2: RQL_STATE - RISC list state byte - free, ready, done, aborted (1 byte)
- * 3: RQL_TID - request target id (1 byte)
- * 4: RQL_PHYADDR - ADV_SCSI_REQ_Q physical pointer (4 bytes)
- *
- * Return:
- *      ADV_SUCCESS(1) - the request is in the mailbox
- *      ADV_BUSY(0) - total request count > 253, try later
- */
-STATIC int
-AdvSendScsiCmd(
-    ADV_DVC_VAR *asc_dvc,
-    ADV_SCSI_REQ_Q  *scsiq)
-{
-    ushort                 next_ready_loc;
-    uchar                  next_ready_loc_fwd;
-    int                    last_int_level;
-    AdvPortAddr            iop_base;
-    long                   req_size;
-    ulong                  q_phy_addr;
-
-    /*
-     * The ADV_SCSI_REQ_Q 'target_id' field should never be equal
-     * to the host adapter ID or exceed ADV_MAX_TID.
-     */
-    if (scsiq->target_id == asc_dvc->chip_scsi_id ||
-        scsiq->target_id > ADV_MAX_TID)
-    {
-        scsiq->host_status = QHSTA_M_INVALID_DEVICE;
-        scsiq->done_status = QD_WITH_ERROR;
-        return ADV_ERROR;
+        AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP);
     }
 
-    iop_base = asc_dvc->iop_base;
-
-    last_int_level = DvcEnterCritical();
-
-    if (asc_dvc->cur_host_qng >= asc_dvc->max_host_qng)
-    {
-        DvcLeaveCritical(last_int_level);
-        return ADV_BUSY;
-    } else
+    /* Wait for up to 100 millisecond for the idle command to timeout. */
+    for (i = 0; i < SCSI_WAIT_100_MSEC; i++)
     {
-        ADV_ASSERT(asc_dvc->cur_host_qng < ASC_MC_RISC_Q_TOTAL_CNT);
-        asc_dvc->cur_host_qng++;
+        /* Poll once each microsecond for command completion. */
+        for (j = 0; j < SCSI_US_PER_MSEC; j++)
+        {
+            AdvReadWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS, result);
+            if (result != 0)
+            {
+                DvcLeaveCritical(last_int_level);
+                return result;
+            }
+            DvcDelayMicroSecond(asc_dvc, (ushort) 1);
+        }
     }
 
-    /*
-     * Clear the ADV_SCSI_REQ_Q done flag.
-     */
-    scsiq->a_flag &= ~ADV_SCSIQ_DONE;
-
-    /*
-     * Save the original sense buffer length.
-     *
-     * After the request completes 'sense_len' will be set to the residual
-     * byte count of the Auto-Request Sense if a command returns CHECK
-     * CONDITION and the Sense Data is valid indicated by 'host_status' not
-     * being set to QHSTA_M_AUTO_REQ_SENSE_FAIL. To determine the valid
-     * Sense Data Length subtract 'sense_len' from 'orig_sense_len'.
-     */
-    scsiq->orig_sense_len = scsiq->sense_len;
-
-    AdvReadByteLram(iop_base, ASC_MC_HOST_NEXT_READY, next_ready_loc);
-    next_ready_loc = ASC_MC_RISC_Q_LIST_BASE +
-        (next_ready_loc * ASC_MC_RISC_Q_LIST_SIZE);
-
-    /*
-     * Write the physical address of the Q to the mailbox.
-     * We need to skip the first four bytes, because the microcode
-     * uses them internally for linking Q's together.
-     */
-    req_size = sizeof(ADV_SCSI_REQ_Q);
-    q_phy_addr = DvcGetPhyAddr(asc_dvc, scsiq,
-                    (uchar *) scsiq, &req_size,
-                    ADV_IS_SCSIQ_FLAG);
-    ADV_ASSERT(ADV_DWALIGN(q_phy_addr) == q_phy_addr);
-    ADV_ASSERT(req_size >= sizeof(ADV_SCSI_REQ_Q));
-
-    scsiq->scsiq_ptr = (ADV_SCSI_REQ_Q *) scsiq;
-
-    /*
-     * The RISC list structure, which 'next_ready_loc' is a pointer
-     * to in microcode LRAM, has the format detailed in the comment
-     * header for this function.
-     *
-     * Write the ADV_SCSI_REQ_Q physical pointer to 'next_ready_loc' request.
-     */
-    AdvWriteDWordLram(iop_base, next_ready_loc + RQL_PHYADDR, q_phy_addr);
-
-    /* Write target_id to 'next_ready_loc' request. */
-    AdvWriteByteLram(iop_base, next_ready_loc + RQL_TID, scsiq->target_id);
-
-    /*
-     * Set the ASC_MC_HOST_NEXT_READY (0x128) microcode variable to
-     * the 'next_ready_loc' request forward pointer.
-     *
-     * Do this *before* changing the 'next_ready_loc' queue to QS_READY.
-     * After the state is changed to QS_READY 'RQL_FWD' will be changed
-     * by the microcode.
-     *
-     * NOTE: The temporary variable 'next_ready_loc_fwd' is required to
-     * prevent some compilers from optimizing out 'AdvReadByteLram()' if
-     * it were used as the 3rd argument to 'AdvWriteByteLram()'.
-     */
-    AdvReadByteLram(iop_base, next_ready_loc + RQL_FWD, next_ready_loc_fwd);
-    AdvWriteByteLram(iop_base, ASC_MC_HOST_NEXT_READY, next_ready_loc_fwd);
-
-    /*
-     * Change the state of 'next_ready_loc' request from QS_FREE to
-     * QS_READY which will cause the microcode to pick it up and
-     * execute it.
-     *
-     * Can't reference 'next_ready_loc' after changing the request
-     * state to QS_READY. The microcode now owns the request.
-     */
-    AdvWriteByteLram(iop_base, next_ready_loc + RQL_STATE, ASC_MC_QS_READY);
-
+    ADV_ASSERT(0); /* The idle command should never timeout. */
     DvcLeaveCritical(last_int_level);
-    return ADV_SUCCESS;
+    return ADV_ERROR;
 }
 
 /*
  * Inquiry Information Byte 7 Handling
  *
  * Handle SCSI Inquiry Command information for a device by setting
- * microcode operating variables that affect WDTR, SDTR, and Tag 
+ * microcode operating variables that affect WDTR, SDTR, and Tag
  * Queuing.
  */
 STATIC void
 AdvInquiryHandling(
-    ADV_DVC_VAR          *asc_dvc,
-    ADV_SCSI_REQ_Q       *scsiq)
+    ADV_DVC_VAR                 *asc_dvc,
+    ADV_SCSI_REQ_Q              *scsiq)
 {
-    AdvPortAddr          iop_base;
-    uchar                tid;
-    ASC_SCSI_INQUIRY     *inq;
-    ushort               tidmask;
-    ushort               cfg_word;
+    AdvPortAddr                 iop_base;
+    uchar                       tid;
+    ADV_SCSI_INQUIRY            *inq;
+    ushort                      tidmask;
+    ushort                      cfg_word;
 
     /*
      * AdvInquiryHandling() requires up to INQUIRY information Byte 7
@@ -15318,6 +17958,7 @@ AdvInquiryHandling(
      * length and the ADV_SCSI_REQ_Q 'data_cnt' field is set by the
      * microcode to the transfer residual count.
      */
+
     if (scsiq->cdb[4] < 8 || (scsiq->cdb[4] - scsiq->data_cnt) < 8)
     {
         return;
@@ -15325,12 +17966,13 @@ AdvInquiryHandling(
 
     iop_base = asc_dvc->iop_base;
     tid = scsiq->target_id;
-    inq = (ASC_SCSI_INQUIRY *) scsiq->vdata_addr;
+
+    inq = (ADV_SCSI_INQUIRY *) scsiq->vdata_addr;
 
     /*
      * WDTR, SDTR, and Tag Queuing cannot be enabled for old devices.
      */
-    if (inq->byte3.rsp_data_fmt < 2 && inq->byte2.ansi_apr_ver < 2)
+    if (inq->rsp_data_fmt < 2 && inq->ansi_apr_ver < 2)
     {
         return;
     } else
@@ -15354,7 +17996,7 @@ AdvInquiryHandling(
          * device's 'wdtr_able' bit and write the new value to the
          * microcode.
          */
-        if ((asc_dvc->wdtr_able & tidmask) && inq->byte7.WBus16)
+        if ((asc_dvc->wdtr_able & tidmask) && inq->WBus16)
         {
             AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
             if ((cfg_word & tidmask) == 0)
@@ -15363,10 +18005,15 @@ AdvInquiryHandling(
                 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
 
                 /*
-                 * Clear the microcode "WDTR negotiation" done indicator
-                 * for the target to cause it to negotiate with the new
-                 * setting set above.
+                 * Clear the microcode "SDTR negotiation" and "WDTR
+                 * negotiation" done indicators for the target to cause
+                 * it to negotiate with the new setting set above.
+                 * WDTR when accepted causes the target to enter
+                 * asynchronous mode, so SDTR must be negotiated.
                  */
+                AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
+                cfg_word &= ~tidmask;
+                AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
                 AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word);
                 cfg_word &= ~tidmask;
                 AdvWriteWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word);
@@ -15380,7 +18027,7 @@ AdvInquiryHandling(
          * supports synchronous transfers, then turn on the device's
          * 'sdtr_able' bit. Write the new value to the microcode.
          */
-        if ((asc_dvc->sdtr_able & tidmask) && inq->byte7.Sync)
+        if ((asc_dvc->sdtr_able & tidmask) && inq->Sync)
         {
             AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
             if ((cfg_word & tidmask) == 0)
@@ -15400,8 +18047,8 @@ AdvInquiryHandling(
         }
 
         /*
-         * If the EEPROM enabled Tag Queuing for device and the
-         * device supports Tag Queuing, then turn on the device's
+         * If the EEPROM enabled Tag Queuing for the device and the
+         * device supports Tag Queueing, then turn on the device's
          * 'tagqng_enable' bit in the microcode and set the microcode
          * maximum command count to the ADV_DVC_VAR 'max_dvc_qng'
          * value.
@@ -15411,11 +18058,12 @@ AdvInquiryHandling(
          * disabling Tag Queuing in the BIOS devices with Tag Queuing
          * bugs will at least work with the BIOS.
          */
-        if ((asc_dvc->tagqng_able & tidmask) && inq->byte7.CmdQue)
+        if ((asc_dvc->tagqng_able & tidmask) && inq->CmdQue)
         {
             AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word);
             cfg_word |= tidmask;
             AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word);
+
             AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
                 asc_dvc->max_dvc_qng);
         }
index bc5652a09c2695681e75f2e2592cafbdbda9cf1f..86752c011a9bd35755bfc179cdc9e42485e2220f 100644 (file)
  * 09/24/98 hl - v1.01b Fixed reset.
  * 10/05/98 hl - v1.02 split the source code and release.
  * 12/19/98 bv - v1.02a Use spinlocks for 2.1.95 and up
+ * 01/31/99 bv - v1.02b Use mdelay instead of waitForPause
+ * 08/08/99 bv - v1.02c Use waitForPause again.
  **************************************************************************/
 
 #ifndef CVT_LINUX_VERSION
 #define CVT_LINUX_VERSION(V,P,S)        (V * 65536 + P * 256 + S)
 #endif
 
+#include <linux/version.h>
 #include <linux/sched.h>
 #include <asm/io.h>
 #include "i60uscsi.h"
 
+#define JIFFIES_TO_MS(t) ((t) * 1000 / HZ)
+#define MS_TO_JIFFIES(j) ((j * HZ) / 1000)
 
 /* ---- INTERNAL FUNCTIONS ---- */
 static UCHAR waitChipReady(ORC_HCS * hcsp);
@@ -155,7 +160,7 @@ static UCHAR dftNvRam[64] =
 /***************************************************************************/
 static void waitForPause(unsigned amount)
 {
-       ULONG the_time = jiffies + amount;      /* 0.01 seconds per jiffy */
+       ULONG the_time = jiffies + MS_TO_JIFFIES(amount);
 
 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
        while (time_before_eq(jiffies, the_time));
@@ -169,10 +174,10 @@ UCHAR waitChipReady(ORC_HCS * hcsp)
 {
        int i;
 
-       for (i = 0; i < 2000; i++) {    /* Wait 1 second for report timeout     */
+       for (i = 0; i < 10; i++) {      /* Wait 1 second for report timeout     */
                if (ORC_RD(hcsp->HCS_Base, ORC_HCTRL) & HOSTSTOP)       /* Wait HOSTSTOP set */
                        return (TRUE);
-               waitForPause(5);        /* wait 500ms before try again  */
+               waitForPause(100);      /* wait 100ms before try again  */
        }
        return (FALSE);
 }
@@ -182,10 +187,10 @@ UCHAR waitFWReady(ORC_HCS * hcsp)
 {
        int i;
 
-       for (i = 0; i < 2000; i++) {    /* Wait 1 second for report timeout     */
+       for (i = 0; i < 10; i++) {      /* Wait 1 second for report timeout     */
                if (ORC_RD(hcsp->HCS_Base, ORC_HSTUS) & RREADY)         /* Wait READY set */
                        return (TRUE);
-               waitForPause(5);        /* wait 500ms before try again  */
+               waitForPause(100);      /* wait 100ms before try again  */
        }
        return (FALSE);
 }
@@ -195,10 +200,10 @@ UCHAR waitSCSIRSTdone(ORC_HCS * hcsp)
 {
        int i;
 
-       for (i = 0; i < 2000; i++) {    /* Wait 1 second for report timeout     */
+       for (i = 0; i < 10; i++) {      /* Wait 1 second for report timeout     */
                if (!(ORC_RD(hcsp->HCS_Base, ORC_HCTRL) & SCSIRST))     /* Wait SCSIRST done */
                        return (TRUE);
-               waitForPause(5);        /* wait 500ms before try again  */
+               waitForPause(100);      /* wait 100ms before try again  */
        }
        return (FALSE);
 }
@@ -208,10 +213,10 @@ UCHAR waitHDOoff(ORC_HCS * hcsp)
 {
        int i;
 
-       for (i = 0; i < 2000; i++) {    /* Wait 1 second for report timeout     */
+       for (i = 0; i < 10; i++) {      /* Wait 1 second for report timeout     */
                if (!(ORC_RD(hcsp->HCS_Base, ORC_HCTRL) & HDO))         /* Wait HDO off */
                        return (TRUE);
-               waitForPause(5);        /* wait 500ms before try again  */
+               waitForPause(100);      /* wait 100ms before try again  */
        }
        return (FALSE);
 }
@@ -221,10 +226,10 @@ UCHAR waitHDIset(ORC_HCS * hcsp, UCHAR * pData)
 {
        int i;
 
-       for (i = 0; i < 2000; i++) {    /* Wait 1 second for report timeout     */
+       for (i = 0; i < 10; i++) {      /* Wait 1 second for report timeout     */
                if ((*pData = ORC_RD(hcsp->HCS_Base, ORC_HSTUS)) & HDI)
                        return (TRUE);  /* Wait HDI set */
-               waitForPause(5);        /* wait 500ms before try again  */
+               waitForPause(100);      /* wait 100ms before try again  */
        }
        return (FALSE);
 }
@@ -463,15 +468,9 @@ void setup_SCBs(ORC_HCS * hcsp)
        pVirEscb = (ESCB *) hcsp->HCS_virEscbArray;
 
        for (i = 0; i < orc_num_scb; i++) {
-#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
-               pPhysEscb = (PVOID) ((ULONG) hcsp->HCS_virEscbArray + (sizeof(ESCB) * i));
-               pVirScb->SCB_SGPAddr = (U32) VIRT_TO_BUS(pPhysEscb);
-               pVirScb->SCB_SensePAddr = (U32) VIRT_TO_BUS(pPhysEscb);
-#else
                pPhysEscb = (PVOID) (hcsp->HCS_physEscbArray + (sizeof(ESCB) * i));
                pVirScb->SCB_SGPAddr = (U32) pPhysEscb;
                pVirScb->SCB_SensePAddr = (U32) pPhysEscb;
-#endif
                pVirScb->SCB_EScb = pVirEscb;
                pVirScb->SCB_ScbIdx = i;
                pVirScb++;
index 6fff823cc2fd2619b2b206f7303563a3324c17ec..1c48c6e17f71ad65f024479d2a5fb5c0e2c3296c 100644 (file)
@@ -60,8 +60,6 @@
  *     12/19/98 bv, v1.02a Use spinlocks for 2.1.95 and up.
  **************************************************************************/
 
-#include <linux/config.h>
-
 #define ULONG   unsigned long
 #define PVOID   void *
 #define USHORT  unsigned short
index 04ecc1511996c37dbe6b2eca85b55e588b93697d..33b2f82d8371a8edd3c1572e3392c38bed773d13 100644 (file)
@@ -1845,7 +1845,7 @@ static char setup_buffer[SETUP_BUFFER_SIZE];
 static char setup_used[MAX_SETUP_ARGS];
 static int done_setup = 0;
 
-in2000__INITFUNC( void in2000_setup (char *str, int *ints) )
+void __init in2000_setup (char *str, int *ints)
 {
 int i;
 char *p1,*p2;
@@ -1877,7 +1877,7 @@ char *p1,*p2;
 /* check_setup_args() returns index if key found, 0 if not
  */
 
-in2000__INITFUNC( static int check_setup_args(char *key, int *flags, int *val, char *buf) )
+static int __init check_setup_args(char *key, int *flags, int *val, char *buf)
 {
 int x;
 char *cp;
@@ -1931,7 +1931,7 @@ static const int int_tab[] in2000__INITDATA = {
    };
 
 
-in2000__INITFUNC( int in2000_detect(Scsi_Host_Template * tpnt) )
+int __init in2000_detect(Scsi_Host_Template * tpnt)
 {
 struct Scsi_Host *instance;
 struct IN2000_hostdata *hostdata;
index 0e40264eddb369168204ec30ed81c67096d289e1..679bafc000ede529a34eb115ae913edcbaa25833 100644 (file)
 
 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
 #include <stdarg.h>
+#include <asm/io.h>
 #include <asm/irq.h>
+#include <linux/string.h>
 #include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
 #include <linux/delay.h>
+#include <linux/sched.h>
 #if LINUX_VERSION_CODE <= CVT_LINUX_VERSION(2,1,92)
 #include <linux/bios32.h>
 #endif
 #include <linux/pci.h>
+#include <linux/proc_fs.h>
 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,23)
 #include <linux/init.h>
 #endif
 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
 #include <asm/spinlock.h>
 #endif
+#include "sd.h"
+#include "scsi.h"
+#include "hosts.h"
+#include "inia100.h"
 #include <linux/stat.h>
+#include <linux/malloc.h>
+#include <linux/config.h>
+
 
 #else
 
+#include <linux/kernel.h>
 #include <linux/head.h>
 #include <linux/types.h>
-#include <asm/system.h>
-#include "../block/blk.h"
-#endif
-
-#include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/ioport.h>
+
 #include <linux/sched.h>
 #include <linux/proc_fs.h>
+#include <asm/system.h>
 #include <asm/io.h>
+#include "../block/blk.h"
 #include "scsi.h"
 #include "sd.h"
 #include "hosts.h"
 #include <linux/malloc.h>
 #include "inia100.h"
+#endif
 
 #ifdef MODULE
 Scsi_Host_Template driver_template = INIA100;
@@ -119,7 +132,7 @@ Scsi_Host_Template driver_template = INIA100;
 char *inia100_Copyright = "Copyright (C) 1998-99";
 char *inia100_InitioName = "by Initio Corporation";
 char *inia100_ProductName = "INI-A100U2W";
-char *inia100_Version = "v1.02a";
+char *inia100_Version = "v1.02c";
 
 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
 struct proc_dir_entry proc_scsi_inia100 =
index e269ea7bcc68d02f18719ea222bcd5f134973d1f..51d63a589d8a3ef06c340cbe67576f71496f9d6d 100644 (file)
@@ -83,7 +83,7 @@ extern struct proc_dir_entry proc_scsi_inia100;
 extern int inia100_biosparam(Disk *, int, int *);      /*for linux v1.13 */
 #endif
 
-#define inia100_REVID "Initio INI-A100U2W SCSI device driver; Revision: 1.02a"
+#define inia100_REVID "Initio INI-A100U2W SCSI device driver; Revision: 1.02c"
 
 #if LINUX_VERSION_CODE < CVT_LINUX_VERSION(1, 3, 0)
 #define INIA100        { \
index 03aa3346cff19d48a4563bac509a7bf74d6e50a4..061ab723952bc27249bc8691610d8f687886015b 100644 (file)
@@ -928,13 +928,14 @@ void get_sectorsize(int i){
        scsi_CDs[i].sector_size = 2048;  /* A guess, just in case */
        scsi_CDs[i].needs_sector_size = 1;
     } else {
+#if 0
        if (cdrom_get_last_written(MKDEV(MAJOR_NR, i),
-          (long*)&scsi_CDs[i].capacity)) {
+          (long*)&scsi_CDs[i].capacity))
+#endif
                scsi_CDs[i].capacity = 1 + ((buffer[0] << 24) |
                                            (buffer[1] << 16) |
                                            (buffer[2] << 8) |
                                             buffer[3]);
-       }
        scsi_CDs[i].sector_size = (buffer[4] << 24) |
            (buffer[5] << 16) | (buffer[6] << 8) | buffer[7];
        switch (scsi_CDs[i].sector_size) {
index fdae0e0dbd63d5f27b77fde9c1644ee483b3b680..28833c08654ae9ccda1a20473826853254c6a5a2 100644 (file)
@@ -13,6 +13,9 @@ dep_tristate 'C-Media PCI (CMI8338/8378)' CONFIG_SOUND_CMPCI $CONFIG_SOUND
 dep_tristate 'Ensoniq AudioPCI (ES1370)' CONFIG_SOUND_ES1370 $CONFIG_SOUND
 dep_tristate 'Creative Ensoniq AudioPCI 97 (ES1371)' CONFIG_SOUND_ES1371 $CONFIG_SOUND
 dep_tristate 'ESS Technology Solo1' CONFIG_SOUND_ESSSOLO1 $CONFIG_SOUND
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+    dep_tristate 'ESS Maestro, Maestro2, Maestro2E driver' CONFIG_SOUND_MAESTRO $CONFIG_SOUND
+fi
 dep_tristate 'S3 SonicVibes' CONFIG_SOUND_SONICVIBES $CONFIG_SOUND
 if [ "$CONFIG_VISWS" = "y" ]; then
     dep_tristate 'SGI Visual Workstation Sound' CONFIG_SOUND_VWSND $CONFIG_SOUND
index 587c0085c0a1e222a7394e72b0c8d15aeb8304c8..5a669a69455ee11798bfdd637e7421d0f93d39a3 100644 (file)
  *                     removed CONFIG_SOUND_ES1370_JOYPORT_BOOT kludge
  *    12.08.99   0.27  module_init/__setup fixes
  *    19.08.99   0.28  SOUND_MIXER_IMIX fixes, reported by Gianluca <gialluca@mail.tiscalinet.it>
+ *    31.08.99   0.29  add spin_lock_init
+ *                     __initlocaldata to fix gcc 2.7.x problems
+ *                     replaced current->state = x with set_current_state(x)
  *
  * some important things missing in Ensoniq documentation:
  *
@@ -1059,7 +1062,7 @@ static int drain_dac1(struct es1370_state *s, int nonblock)
        
        if (s->dma_dac1.mapped || !s->dma_dac1.ready)
                return 0;
-        current->state = TASK_INTERRUPTIBLE;
+        __set_current_state(TASK_INTERRUPTIBLE);
         add_wait_queue(&s->dma_dac1.wait, &wait);
         for (;;) {
                 spin_lock_irqsave(&s->lock, flags);
@@ -1071,7 +1074,7 @@ static int drain_dac1(struct es1370_state *s, int nonblock)
                         break;
                 if (nonblock) {
                         remove_wait_queue(&s->dma_dac1.wait, &wait);
-                        current->state = TASK_RUNNING;
+                        set_current_state(TASK_RUNNING);
                         return -EBUSY;
                 }
                tmo = 3 * HZ * (count + s->dma_dac1.fragsize) / 2
@@ -1081,7 +1084,7 @@ static int drain_dac1(struct es1370_state *s, int nonblock)
                        DBG(printk(KERN_DEBUG "es1370: dma timed out??\n");)
         }
         remove_wait_queue(&s->dma_dac1.wait, &wait);
-        current->state = TASK_RUNNING;
+        set_current_state(TASK_RUNNING);
         if (signal_pending(current))
                 return -ERESTARTSYS;
         return 0;
@@ -1095,7 +1098,7 @@ static int drain_dac2(struct es1370_state *s, int nonblock)
 
        if (s->dma_dac2.mapped || !s->dma_dac2.ready)
                return 0;
-        current->state = TASK_INTERRUPTIBLE;
+        __set_current_state(TASK_INTERRUPTIBLE);
         add_wait_queue(&s->dma_dac2.wait, &wait);
         for (;;) {
                 spin_lock_irqsave(&s->lock, flags);
@@ -1107,7 +1110,7 @@ static int drain_dac2(struct es1370_state *s, int nonblock)
                         break;
                 if (nonblock) {
                         remove_wait_queue(&s->dma_dac2.wait, &wait);
-                        current->state = TASK_RUNNING;
+                        set_current_state(TASK_RUNNING);
                         return -EBUSY;
                 }
                tmo = 3 * HZ * (count + s->dma_dac2.fragsize) / 2
@@ -1117,7 +1120,7 @@ static int drain_dac2(struct es1370_state *s, int nonblock)
                        DBG(printk(KERN_DEBUG "es1370: dma timed out??\n");)
         }
         remove_wait_queue(&s->dma_dac2.wait, &wait);
-        current->state = TASK_RUNNING;
+        set_current_state(TASK_RUNNING);
         if (signal_pending(current))
                 return -ERESTARTSYS;
         return 0;
@@ -2246,7 +2249,7 @@ static int es1370_midi_release(struct inode *inode, struct file *file)
        VALIDATE_STATE(s);
 
        if (file->f_mode & FMODE_WRITE) {
-               current->state = TASK_INTERRUPTIBLE;
+               __set_current_state(TASK_INTERRUPTIBLE);
                add_wait_queue(&s->midi.owait, &wait);
                for (;;) {
                        spin_lock_irqsave(&s->lock, flags);
@@ -2258,7 +2261,7 @@ static int es1370_midi_release(struct inode *inode, struct file *file)
                                break;
                        if (file->f_flags & O_NONBLOCK) {
                                remove_wait_queue(&s->midi.owait, &wait);
-                               current->state = TASK_RUNNING;
+                               set_current_state(TASK_RUNNING);
                                return -EBUSY;
                        }
                        tmo = (count * HZ) / 3100;
@@ -2266,7 +2269,7 @@ static int es1370_midi_release(struct inode *inode, struct file *file)
                                DBG(printk(KERN_DEBUG "es1370: midi timed out??\n");)
                }
                remove_wait_queue(&s->midi.owait, &wait);
-               current->state = TASK_RUNNING;
+               set_current_state(TASK_RUNNING);
        }
        down(&s->open_sem);
        s->open_mode &= (~(file->f_mode << FMODE_MIDI_SHIFT)) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE);
@@ -2337,6 +2340,11 @@ static struct initvol {
        { SOUND_MIXER_WRITE_OGAIN, 0x4040 }
 };
 
+#define RSRCISIOREGION(dev,num) ((dev)->resource[(num)].start != 0 && \
+                                ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
+#define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start)
+
+
 static int __init init_es1370(void)
 {
        struct es1370_state *s;
@@ -2346,11 +2354,10 @@ static int __init init_es1370(void)
 
        if (!pci_present())   /* No PCI bus in this machine! */
                return -ENODEV;
-       printk(KERN_INFO "es1370: version v0.28 time " __TIME__ " " __DATE__ "\n");
+       printk(KERN_INFO "es1370: version v0.29 time " __TIME__ " " __DATE__ "\n");
        while (index < NR_DEVICE && 
               (pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1370, pcidev))) {
-               if (pcidev->resource[0].flags == 0 || 
-                   (pcidev->resource[0].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
+               if (!RSRCISIOREGION(pcidev, 0))
                        continue;
                if (pcidev->irq == 0) 
                        continue;
@@ -2366,8 +2373,9 @@ static int __init init_es1370(void)
                init_waitqueue_head(&s->midi.iwait);
                init_waitqueue_head(&s->midi.owait);
                init_MUTEX(&s->open_sem);
+               spin_lock_init(&s->lock);
                s->magic = ES1370_MAGIC;
-               s->io = pcidev->resource[0].start;
+               s->io = RSRCADDRESS(pcidev, 0);
                s->irq = pcidev->irq;
                if (check_region(s->io, ES1370_EXTENT)) {
                        printk(KERN_ERR "es1370: io ports %#lx-%#lx in use\n", s->io, s->io+ES1370_EXTENT-1);
@@ -2485,11 +2493,12 @@ module_exit(cleanup_es1370);
 
 static int __init es1370_setup(char *str)
 {
-       static unsigned __initdata nr_dev = 0;
+       static unsigned __initlocaldata nr_dev = 0;
 
        if (nr_dev >= NR_DEVICE)
                return 0;
 
+       (void)
        (   (get_option(&str,&joystick[nr_dev]) == 2)
         && (get_option(&str,&lineout [nr_dev]) == 2)
         &&  get_option(&str,&micbias [nr_dev])
index 1055f7206ad0ff4464bfdc9faa625e0a435273e3..f3f543c7ced18cf21793e7ce99cfb9ad37cd1971 100644 (file)
@@ -81,6 +81,9 @@
  *                     added a /proc file system for dumping hardware state
  *                     updated SRC and CODEC w/r functions to accomodate bugs
  *                     in some versions of the ES137x chips.
+ *    31.08.99   0.17  add spin_lock_init
+ *                     __initlocaldata to fix gcc 2.7.x problems
+ *                     replaced current->state = x with set_current_state(x)
  *
  */
 
@@ -1608,8 +1611,8 @@ static int drain_dac1(struct es1371_state *s, int nonblock)
        if (s->dma_dac1.mapped || !s->dma_dac1.ready)
                return 0;
 
+        __set_current_state(TASK_INTERRUPTIBLE);
         add_wait_queue(&s->dma_dac1.wait, &wait);
-        current->state = TASK_INTERRUPTIBLE;
         for (;;) {
                 spin_lock_irqsave(&s->lock, flags);
                count = s->dma_dac1.count;
@@ -1620,7 +1623,7 @@ static int drain_dac1(struct es1371_state *s, int nonblock)
                         break;
                 if (nonblock) {
                         remove_wait_queue(&s->dma_dac1.wait, &wait);
-                        current->state = TASK_RUNNING;
+                        set_current_state(TASK_RUNNING);
                         return -EBUSY;
                 }
                tmo = 3 * HZ * (count + s->dma_dac1.fragsize) / 2 / s->dac1rate;
@@ -1629,7 +1632,7 @@ static int drain_dac1(struct es1371_state *s, int nonblock)
                        printk(KERN_DEBUG "es1371: dac1 dma timed out??\n");
         }
         remove_wait_queue(&s->dma_dac1.wait, &wait);
-        current->state = TASK_RUNNING;
+        set_current_state(TASK_RUNNING);
         if (signal_pending(current))
                 return -ERESTARTSYS;
         return 0;
@@ -1644,8 +1647,8 @@ static int drain_dac2(struct es1371_state *s, int nonblock)
        if (s->dma_dac2.mapped || !s->dma_dac2.ready)
                return 0;
 
+        __set_current_state(TASK_UNINTERRUPTIBLE);
         add_wait_queue(&s->dma_dac2.wait, &wait);
-        current->state = TASK_UNINTERRUPTIBLE;
         for (;;) {
                 spin_lock_irqsave(&s->lock, flags);
                count = s->dma_dac2.count;
@@ -1656,7 +1659,7 @@ static int drain_dac2(struct es1371_state *s, int nonblock)
                         break;
                 if (nonblock) {
                         remove_wait_queue(&s->dma_dac2.wait, &wait);
-                        current->state = TASK_RUNNING;
+                        set_current_state(TASK_RUNNING);
                         return -EBUSY;
                 }
                tmo = 3 * HZ * (count + s->dma_dac2.fragsize) / 2 / s->dac2rate;
@@ -1665,7 +1668,7 @@ static int drain_dac2(struct es1371_state *s, int nonblock)
                        printk(KERN_DEBUG "es1371: dac2 dma timed out??\n");
         }
         remove_wait_queue(&s->dma_dac2.wait, &wait);
-        current->state = TASK_RUNNING;
+        set_current_state(TASK_RUNNING);
         if (signal_pending(current))
                 return -ERESTARTSYS;
         return 0;
@@ -2781,7 +2784,7 @@ static int es1371_midi_release(struct inode *inode, struct file *file)
 
        VALIDATE_STATE(s);
        if (file->f_mode & FMODE_WRITE) {
-               current->state = TASK_INTERRUPTIBLE;
+               __set_current_state(TASK_INTERRUPTIBLE);
                add_wait_queue(&s->midi.owait, &wait);
                for (;;) {
                        spin_lock_irqsave(&s->lock, flags);
@@ -2793,7 +2796,7 @@ static int es1371_midi_release(struct inode *inode, struct file *file)
                                break;
                        if (file->f_flags & O_NONBLOCK) {
                                remove_wait_queue(&s->midi.owait, &wait);
-                               current->state = TASK_RUNNING;
+                               set_current_state(TASK_RUNNING);
                                return -EBUSY;
                        }
                        tmo = (count * HZ) / 3100;
@@ -2801,7 +2804,7 @@ static int es1371_midi_release(struct inode *inode, struct file *file)
                                printk(KERN_DEBUG "es1371: midi timed out??\n");
                }
                remove_wait_queue(&s->midi.owait, &wait);
-               current->state = TASK_RUNNING;
+               set_current_state(TASK_RUNNING);
        }
        down(&s->open_sem);
        s->open_mode &= (~(file->f_mode << FMODE_MIDI_SHIFT)) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE);
@@ -2910,6 +2913,11 @@ static struct initvol {
        { SOUND_MIXER_WRITE_IGAIN, 0x4040 }
 };
 
+#define RSRCISIOREGION(dev,num) ((dev)->resource[(num)].start != 0 && \
+                                ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
+#define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start)
+
+
 static int __init init_es1371(void)
 {
        struct es1371_state *s;
@@ -2920,11 +2928,10 @@ static int __init init_es1371(void)
 
        if (!pci_present())   /* No PCI bus in this machine! */
                return -ENODEV;
-       printk(KERN_INFO "es1371: version v0.15 time " __TIME__ " " __DATE__ "\n");
+       printk(KERN_INFO "es1371: version v0.17 time " __TIME__ " " __DATE__ "\n");
        while (index < NR_DEVICE && 
               (pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1371, pcidev))) {
-               if (pcidev->resource[0].flags == 0 || 
-                   (pcidev->resource[0].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
+               if (!RSRCISIOREGION(pcidev, 0))
                        continue;
                if (pcidev->irq == 0) 
                        continue;
@@ -2940,8 +2947,9 @@ static int __init init_es1371(void)
                init_waitqueue_head(&s->midi.iwait);
                init_waitqueue_head(&s->midi.owait);
                init_MUTEX(&s->open_sem);
+               spin_lock_init(&s->lock);
                s->magic = ES1371_MAGIC;
-               s->io = pcidev->resource[0].start;
+               s->io = RSRCADDRESS(pcidev, 0);
                s->irq = pcidev->irq;
                pci_read_config_byte(pcidev, PCI_REVISION_ID, &s->rev);
                if (check_region(s->io, ES1371_EXTENT)) {
@@ -3106,12 +3114,12 @@ module_exit(cleanup_es1371);
 
 static int __init es1371_setup(char *str)
 {
-       static unsigned __initdata nr_dev = 0;
+       static unsigned __initlocaldata nr_dev = 0;
 
        if (nr_dev >= NR_DEVICE)
                return 0;
        if (get_option(&str, &joystick[nr_dev]) == 2)
-               get_option(&str, &spdif[nr_dev]);
+               (void)get_option(&str, &spdif[nr_dev]);
        nr_dev++;
        return 1;
 }
index 4189dc37c2fa8924b05f4f067ed7e088a526ffbd..463c59517dea84529336fe3275c0d275655f5a9a 100644 (file)
@@ -54,6 +54,8 @@
  *                     The fun part is that the Windows Solo1 driver doesn't
  *                     seem to do these tricks.
  *                     Bugs remaining: plops and clicks when starting/stopping playback
+ *    31.08.99   0.7   add spin_lock_init
+ *                     replaced current->state = x with set_current_state(x)
  *
  */
 
@@ -929,7 +931,7 @@ static int drain_dac(struct solo1_state *s, int nonblock)
        
        if (s->dma_dac.mapped)
                return 0;
-        current->state = TASK_INTERRUPTIBLE;
+        __set_current_state(TASK_INTERRUPTIBLE);
         add_wait_queue(&s->dma_dac.wait, &wait);
         for (;;) {
                 spin_lock_irqsave(&s->lock, flags);
@@ -941,7 +943,7 @@ static int drain_dac(struct solo1_state *s, int nonblock)
                         break;
                 if (nonblock) {
                         remove_wait_queue(&s->dma_dac.wait, &wait);
-                        current->state = TASK_RUNNING;
+                        set_current_state(TASK_RUNNING);
                         return -EBUSY;
                 }
                tmo = 3 * HZ * (count + s->dma_dac.fragsize) / 2 / s->rate;
@@ -953,7 +955,7 @@ static int drain_dac(struct solo1_state *s, int nonblock)
                         printk(KERN_DEBUG "solo1: dma timed out??\n");
         }
         remove_wait_queue(&s->dma_dac.wait, &wait);
-        current->state = TASK_RUNNING;
+        set_current_state(TASK_RUNNING);
         if (signal_pending(current))
                 return -ERESTARTSYS;
         return 0;
@@ -1779,7 +1781,7 @@ static int solo1_midi_release(struct inode *inode, struct file *file)
        VALIDATE_STATE(s);
 
        if (file->f_mode & FMODE_WRITE) {
-               current->state = TASK_INTERRUPTIBLE;
+               __set_current_state(TASK_INTERRUPTIBLE);
                add_wait_queue(&s->midi.owait, &wait);
                for (;;) {
                        spin_lock_irqsave(&s->lock, flags);
@@ -1791,7 +1793,7 @@ static int solo1_midi_release(struct inode *inode, struct file *file)
                                break;
                        if (file->f_flags & O_NONBLOCK) {
                                remove_wait_queue(&s->midi.owait, &wait);
-                               current->state = TASK_RUNNING;
+                               set_current_state(TASK_RUNNING);
                                return -EBUSY;
                        }
                        tmo = (count * HZ) / 3100;
@@ -1799,7 +1801,7 @@ static int solo1_midi_release(struct inode *inode, struct file *file)
                                printk(KERN_DEBUG "solo1: midi timed out??\n");
                }
                remove_wait_queue(&s->midi.owait, &wait);
-               current->state = TASK_RUNNING;
+               set_current_state(TASK_RUNNING);
        }
        down(&s->open_sem);
        s->open_mode &= (~(file->f_mode << FMODE_MIDI_SHIFT)) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE);
@@ -2030,6 +2032,11 @@ static struct initvol {
        { SOUND_MIXER_WRITE_MIC, 0x4040 }
 };
 
+#define RSRCISIOREGION(dev,num) ((dev)->resource[(num)].start != 0 && \
+                                ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
+#define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start)
+
+
 static int __init init_solo1(void)
 {
        struct solo1_state *s;
@@ -2039,17 +2046,13 @@ static int __init init_solo1(void)
 
        if (!pci_present())   /* No PCI bus in this machine! */
                return -ENODEV;
-       printk(KERN_INFO "solo1: version v0.6 time " __TIME__ " " __DATE__ "\n");
+       printk(KERN_INFO "solo1: version v0.7 time " __TIME__ " " __DATE__ "\n");
        while (index < NR_DEVICE && 
               (pcidev = pci_find_device(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_SOLO1, pcidev))) {
-               if (pcidev->resource[0].start == 0 ||
-                   (pcidev->resource[0].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO ||
-                   pcidev->resource[1].start == 0 ||
-                   (pcidev->resource[1].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO ||
-                   pcidev->resource[2].start == 0 ||
-                   (pcidev->resource[2].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO ||
-                   pcidev->resource[3].start == 0 ||
-                   (pcidev->resource[3].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
+               if (!RSRCISIOREGION(pcidev, 0) ||
+                   !RSRCISIOREGION(pcidev, 1) ||
+                   !RSRCISIOREGION(pcidev, 2) ||
+                   !RSRCISIOREGION(pcidev, 3))
                        continue;
                if (pcidev->irq == 0)
                        continue;
@@ -2064,14 +2067,15 @@ static int __init init_solo1(void)
                init_waitqueue_head(&s->midi.iwait);
                init_waitqueue_head(&s->midi.owait);
                init_MUTEX(&s->open_sem);
+               spin_lock_init(&s->lock);
                s->magic = SOLO1_MAGIC;
                s->pcidev = pcidev;
-               s->iobase = pcidev->resource[0].start;
-               s->sbbase = pcidev->resource[1].start;
-               s->vcbase = pcidev->resource[2].start;
+               s->iobase = RSRCADDRESS(pcidev, 0);
+               s->sbbase = RSRCADDRESS(pcidev, 1);
+               s->vcbase = RSRCADDRESS(pcidev, 2);
                s->ddmabase = s->vcbase + DDMABASE_OFFSET;
-               s->mpubase = pcidev->resource[3].start;
-               s->gpbase = pcidev->resource[4].start;
+               s->mpubase = RSRCADDRESS(pcidev, 3);
+               s->gpbase = RSRCADDRESS(pcidev, 4);
                s->irq = pcidev->irq;
                if (check_region(s->iobase, IOBASE_EXTENT) ||
                    check_region(s->sbbase, SBBASE_EXTENT) ||
index c4ac970e75e11e7b58f0dd924d68f4b3503f8f47..923d6b615af012fe809c3164ef6b77eff49e7755 100644 (file)
  *    03.08.99   0.17  adapt to Linus' new __setup/__initcall
  *                     added kernel command line options "sonicvibes=reverb" and "sonicvibesdmaio=dmaioaddr"
  *    12.08.99   0.18  module_init/__setup fixes
+ *    24.08.99   0.19  get rid of the dmaio kludge, replace with allocate_resource
+ *    31.08.99   0.20  add spin_lock_init
+ *                     __initlocaldata to fix gcc 2.7.x problems
+ *                     use new resource allocation to allocate DDMA IO space
+ *                     replaced current->state = x with set_current_state(x)
  *
  */
 
 #define SV_EXTENT_GAME    0x8
 #define SV_EXTENT_DMA     0x10
 
+#define RESOURCE_SB       0
+#define RESOURCE_ENH      1
+#define RESOURCE_SYNTH    2
+#define RESOURCE_MIDI     3
+#define RESOURCE_GAME     4
+#define RESOURCE_DDMA     7
 
 #define SV_MIDI_DATA      0
 #define SV_MIDI_COMMAND   1
@@ -1254,7 +1265,7 @@ static int drain_dac(struct sv_state *s, int nonblock)
 
        if (s->dma_dac.mapped || !s->dma_dac.ready)
                return 0;
-        current->state = TASK_INTERRUPTIBLE;
+        __set_current_state(TASK_INTERRUPTIBLE);
         add_wait_queue(&s->dma_dac.wait, &wait);
         for (;;) {
                 spin_lock_irqsave(&s->lock, flags);
@@ -1266,7 +1277,7 @@ static int drain_dac(struct sv_state *s, int nonblock)
                         break;
                 if (nonblock) {
                         remove_wait_queue(&s->dma_dac.wait, &wait);
-                        current->state = TASK_RUNNING;
+                        set_current_state(TASK_RUNNING);
                         return -EBUSY;
                 }
                tmo = 3 * HZ * (count + s->dma_dac.fragsize) / 2 / s->ratedac;
@@ -1275,7 +1286,7 @@ static int drain_dac(struct sv_state *s, int nonblock)
                        printk(KERN_DEBUG "sv: dma timed out??\n");
         }
         remove_wait_queue(&s->dma_dac.wait, &wait);
-        current->state = TASK_RUNNING;
+        set_current_state(TASK_RUNNING);
         if (signal_pending(current))
                 return -ERESTARTSYS;
         return 0;
@@ -2057,7 +2068,7 @@ static int sv_midi_release(struct inode *inode, struct file *file)
        VALIDATE_STATE(s);
 
        if (file->f_mode & FMODE_WRITE) {
-               current->state = TASK_INTERRUPTIBLE;
+               __set_current_state(TASK_INTERRUPTIBLE);
                add_wait_queue(&s->midi.owait, &wait);
                for (;;) {
                        spin_lock_irqsave(&s->lock, flags);
@@ -2069,7 +2080,7 @@ static int sv_midi_release(struct inode *inode, struct file *file)
                                break;
                        if (file->f_flags & O_NONBLOCK) {
                                remove_wait_queue(&s->midi.owait, &wait);
-                               current->state = TASK_RUNNING;
+                               set_current_state(TASK_RUNNING);
                                return -EBUSY;
                        }
                        tmo = (count * HZ) / 3100;
@@ -2077,7 +2088,7 @@ static int sv_midi_release(struct inode *inode, struct file *file)
                                printk(KERN_DEBUG "sv: midi timed out??\n");
                }
                remove_wait_queue(&s->midi.owait, &wait);
-               current->state = TASK_RUNNING;
+               set_current_state(TASK_RUNNING);
        }
        down(&s->open_sem);
        s->open_mode &= (~(file->f_mode << FMODE_MIDI_SHIFT)) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE);
@@ -2296,8 +2307,6 @@ static int reverb[NR_DEVICE] = { 0, };
 static int wavetable[NR_DEVICE] = { 0, };
 #endif
 
-static unsigned dmaio = 0xac00;
-
 MODULE_PARM(reverb, "1-" __MODULE_STRING(NR_DEVICE) "i");
 MODULE_PARM_DESC(reverb, "if 1 enables the reverb circuitry. NOTE: your card must have the reverb RAM");
 #if 0
@@ -2305,9 +2314,6 @@ MODULE_PARM(wavetable, "1-" __MODULE_STRING(NR_DEVICE) "i");
 MODULE_PARM_DESC(wavetable, "if 1 the wavetable synth is enabled");
 #endif
 
-MODULE_PARM(dmaio, "i");
-MODULE_PARM_DESC(dmaio, "if the motherboard BIOS did not allocate DDMA io, allocate them starting at this address");
-
 MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
 MODULE_DESCRIPTION("S3 SonicVibes Driver");
 
@@ -2328,6 +2334,11 @@ static struct initvol {
        { SOUND_MIXER_WRITE_PCM, 0x4040 }
 };
 
+#define RSRCISIOREGION(dev,num) ((dev)->resource[(num)].start != 0 && \
+                                ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
+#define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start)
+
+
 static int __init init_sonicvibes(void)
 {
        struct sv_state *s;
@@ -2337,24 +2348,31 @@ static int __init init_sonicvibes(void)
 
        if (!pci_present())   /* No PCI bus in this machine! */
                return -ENODEV;
-       printk(KERN_INFO "sv: version v0.18 time " __TIME__ " " __DATE__ "\n");
+       printk(KERN_INFO "sv: version v0.20 time " __TIME__ " " __DATE__ "\n");
 #if 0
        if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT)))
                printk(KERN_INFO "sv: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n");
 #endif
        while (index < NR_DEVICE && 
               (pcidev = pci_find_device(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_SONICVIBES, pcidev))) {
-               if (pcidev->resource[1].flags == 0 || 
-                   (pcidev->resource[1].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
-                       continue;
-               if (pcidev->resource[2].flags == 0 || 
-                   (pcidev->resource[2].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
-                       continue;
-               if (pcidev->resource[3].flags == 0 || 
-                   (pcidev->resource[3].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
+               if (!RSRCISIOREGION(pcidev, RESOURCE_SB) ||
+                   !RSRCISIOREGION(pcidev, RESOURCE_ENH) ||
+                   !RSRCISIOREGION(pcidev, RESOURCE_SYNTH) ||
+                   !RSRCISIOREGION(pcidev, RESOURCE_MIDI) ||
+                   !RSRCISIOREGION(pcidev, RESOURCE_GAME))
                        continue;
                if (pcidev->irq == 0)
                        continue;
+               /* try to allocate a DDMA resource if not already available */
+               if (!RSRCISIOREGION(pcidev, RESOURCE_DDMA)) {
+                       /* take care of ISA aliases */
+                       if (allocate_resource(&ioport_resource, pcidev->resource+RESOURCE_DDMA, 
+                                             2*SV_EXTENT_DMA, 0x1000, 0x10000-2*SV_EXTENT_DMA, 1024)) {
+                               printk(KERN_ERR "sv: cannot allocate DDMA controller io ports\n");
+                               continue;
+                       }
+                       pcidev->resource[RESOURCE_DDMA].flags = PCI_BASE_ADDRESS_SPACE_IO | IORESOURCE_IO;
+               }
                if (!(s = kmalloc(sizeof(struct sv_state), GFP_KERNEL))) {
                        printk(KERN_WARNING "sv: out of memory\n");
                        continue;
@@ -2366,35 +2384,19 @@ static int __init init_sonicvibes(void)
                init_waitqueue_head(&s->midi.iwait);
                init_waitqueue_head(&s->midi.owait);
                init_MUTEX(&s->open_sem);
+               spin_lock_init(&s->lock);
                s->magic = SV_MAGIC;
-               s->iosb = pcidev->resource[0].start;
-               s->ioenh = pcidev->resource[1].start;
-               s->iosynth = pcidev->resource[2].start;
-               s->iomidi = pcidev->resource[3].start;
-               s->iogame = pcidev->resource[4].start;
-               pci_read_config_dword(pcidev, 0x40, &s->iodmaa);
-               pci_read_config_dword(pcidev, 0x48, &s->iodmac);
-               dmaio &= ~(SV_EXTENT_DMA-1);
-               s->iodmaa &= ~(SV_EXTENT_DMA-1);
-               s->iodmac &= ~(SV_EXTENT_DMA-1);
-               if (!(s->iodmaa)) {
-                       s->iodmaa = dmaio;
-                       dmaio += SV_EXTENT_DMA;
-                       printk(KERN_INFO "sv: BIOS did not allocate DDMA channel A io, allocated at %#x\n",
-                              s->iodmaa);
-               }
-               if (!(s->iodmac)) {
-                       s->iodmac = dmaio;
-                       dmaio += SV_EXTENT_DMA;
-                       printk(KERN_INFO "sv: BIOS did not allocate DDMA channel C io, allocated at %#x\n",
-                              s->iodmac);
-               }
+               s->iosb = RSRCADDRESS(pcidev, RESOURCE_SB);
+               s->ioenh = RSRCADDRESS(pcidev, RESOURCE_ENH);
+               s->iosynth = RSRCADDRESS(pcidev, RESOURCE_SYNTH);
+               s->iomidi = RSRCADDRESS(pcidev, RESOURCE_MIDI);
+               s->iogame = RSRCADDRESS(pcidev, RESOURCE_GAME);
+               s->iodmaa = RSRCADDRESS(pcidev, RESOURCE_DDMA);
+               s->iodmac = RSRCADDRESS(pcidev, RESOURCE_DDMA) + SV_EXTENT_DMA;
                pci_write_config_dword(pcidev, 0x40, s->iodmaa | 9);  /* enable and use extended mode */
                pci_write_config_dword(pcidev, 0x48, s->iodmac | 9);  /* enable */
                printk(KERN_DEBUG "sv: io ports: %#lx %#lx %#lx %#lx %#lx %#x %#x\n",
                       s->iosb, s->ioenh, s->iosynth, s->iomidi, s->iogame, s->iodmaa, s->iodmac);
-               if (s->ioenh == 0 || s->iodmaa == 0 || s->iodmac == 0)
-                       continue;
                s->irq = pcidev->irq;
 
                /* hack */
@@ -2436,8 +2438,8 @@ static int __init init_sonicvibes(void)
                wrindir(s, SV_CIDRIVECONTROL, 0);  /* drive current 16mA */
                wrindir(s, SV_CIENABLE, s->enable = 0);  /* disable DMAA and DMAC */
                outb(~(SV_CINTMASK_DMAA | SV_CINTMASK_DMAC), s->ioenh + SV_CODEC_INTMASK);
-               //outb(0xff, s->iodmaa + SV_DMA_RESET);
-               //outb(0xff, s->iodmac + SV_DMA_RESET);
+               /* outb(0xff, s->iodmaa + SV_DMA_RESET); */
+               /* outb(0xff, s->iodmac + SV_DMA_RESET); */
                inb(s->ioenh + SV_CODEC_STATUS); /* ack interrupts */
                wrindir(s, SV_CIADCCLKSOURCE, 0); /* use pll as ADC clock source */
                wrindir(s, SV_CIANALOGPWRDOWN, 0); /* power up the analog parts of the device */
@@ -2550,31 +2552,21 @@ module_exit(cleanup_sonicvibes);
 
 static int __init sonicvibes_setup(char *str)
 {
-       static unsigned __initdata nr_dev = 0;
+       static unsigned __initlocaldata nr_dev = 0;
 
        if (nr_dev >= NR_DEVICE)
                return 0;
 #if 0
        if (get_option(&str, &reverb[nr_dev]) == 2)
-               get_option(&str, &wavetable[nr_dev]);
+               (void)get_option(&str, &wavetable[nr_dev]);
 #else
-       get_option(&str, &reverb[nr_dev]);
+       (void)get_option(&str, &reverb[nr_dev]);
 #endif
 
        nr_dev++;
        return 1;
 }
 
-static int __init sonicvibesdmaio_setup(char *str)
-{
-        int io;
-
-       if (get_option(&str, &io))
-               dmaio = io;
-       return 1;
-}
-
 __setup("sonicvibes=", sonicvibes_setup);
-__setup("sonicvibesdmaio=", sonicvibesdmaio_setup);
 
 #endif /* MODULE */
index 7ad890ee2e4845feebf8eb56ef0778aa8600ad53..bd804e6d98d86bf6d691d5196437478eea3b99c2 100644 (file)
@@ -9,6 +9,7 @@ difficult to maintain, add yourself with a patch if desired.
   ham <ham@unsuave.com>
   Bradley M Keryan <keryan@andrew.cmu.edu>
   Paul Mackerras <paulus@cs.anu.edu.au>
+  David E. Nelson <dnelson@jump.net>
   Vojtech Pavlik <vojtech@twilight.ucw.cz>
   Gregory P. Smith <greg@electricrain.com>
   Linus Torvalds <torvalds@transmeta.com>
index 1df6112940233766229b797486fbaf10c2a9fede..04e688614935a7b525cb8acedc2eaba65276a267 100644 (file)
@@ -28,6 +28,7 @@ if [ ! "$CONFIG_USB" = "n" ]; then
 
   dep_tristate 'USB hub support' CONFIG_USB_HUB $CONFIG_USB
   dep_tristate 'USB mouse support' CONFIG_USB_MOUSE $CONFIG_USB
+  dep_tristate 'USB HP scanner support' CONFIG_USB_HP_SCANNER $CONFIG_USB
   dep_tristate 'USB keyboard support' CONFIG_USB_KBD $CONFIG_USB
   dep_tristate 'USB audio parsing support' CONFIG_USB_AUDIO $CONFIG_USB
   dep_tristate 'USB Communications Device Class (ACM) support' CONFIG_USB_ACM $CONFIG_USB
index f2a98c3b3c79c30c4c7d0189af8f16eeb9ee9cde..0531c15bdf0252fbf32a422b1eb1b1936b4348a0 100644 (file)
@@ -64,6 +64,14 @@ ifeq ($(CONFIG_USB_MOUSE),m)
   MIX_OBJS += mouse.o
 endif
 
+ifeq ($(CONFIG_USB_HP_SCANNER),y)
+  L_OBJS += hp_scanner.o
+endif
+ifeq ($(CONFIG_USB_HP_SCANNER),m)
+  M_OBJS  +=hp_scanner.o
+  MIX_OBJS +=hp_scanner.o
+endif
+
 ifeq ($(CONFIG_USB_HUB),y)
   L_OBJS += hub.o
 endif
diff --git a/drivers/usb/README.hp_scanner b/drivers/usb/README.hp_scanner
new file mode 100644 (file)
index 0000000..ce8c2e5
--- /dev/null
@@ -0,0 +1,59 @@
+August 30, 1999
+
+
+Overview
+
+This README will address issues regarding how to configure the kernel
+to access a USB HP Scanner.  The scanner should support the Scanner
+Control Language (SCL) so that applications such as SANE can access it
+properly.  Refer to the document README.hp_scanner_sane for guidance
+on how to configure SANE to use the USB HP Scanner.
+
+
+Requirements
+
+A host with a USB port.  Ideally, either a UHCI (Intel) or OHCI
+(Compaq and others) hardware port should work.  However, I've only
+been able to really use an OHCI controller.  I did have access to a
+system with a UHCI controller but some very limited testing did not
+produce satisfactory results.
+
+A Linux kernel with USB support (preferably 2.3.15+).
+
+A Linux kernel with USB HP Scanner support.
+
+
+Configuration
+
+Add both USB controller support and USB HP Scanner support using `make
+menuconfig`.  If you decide to use the ohci-hcd driver, don't forget
+to add HUB support.  Compile and install the modules.  Testing was
+performed only as modules, YMMV.
+
+Add a device for the USB scanner: `mknod /dev/usbscanner c 16 1`
+
+Set appropriate permissions for /dev/usbscanner.  Both read and write
+permissions are needed for proper operation.
+
+Load the appropriate modules:
+
+  OHCI:
+
+    modprobe usb-ohci
+    modprobe hp_scanner
+
+  OHCI-HCD:
+    modprobe usb-ohci-hcd
+    modprobe hub
+    modprobe hp_scanner
+
+That's it.  SANE should now be able to access the device.  
+
+There is a small test program (hp_scan.c) that can be used to test the
+scanner device.  It's purpose is to test the driver(s) without having
+to retrieve/configure SANE.  Hp_scan.c will scan the entire bed and
+put the output into a file called out.dat in the current directory.
+The data in the file is raw data.
+
+David /\/elson
+dnelson@jump.net
diff --git a/drivers/usb/README.hp_scanner_sane b/drivers/usb/README.hp_scanner_sane
new file mode 100644 (file)
index 0000000..1cbc8b9
--- /dev/null
@@ -0,0 +1,67 @@
+August 30, 1999
+
+NOTE: This is all VERY alpha.  Use at your own risk.  There is no
+warranty expressed nor implied.
+
+
+Introduction
+
+This document will hopefully provide enough info on how to get SANE
+working with a Hewlett Packard USB capable scanner using the USB
+interface.  The majority of HP Scanners support the Scanner Control
+Language (SCL) which is both published by HP and supported by SANE.
+The only HP Scanner that I'm aware of that does not support SCL is the
+4200C.  All other HP scanners with USB interfaces should work (4100C,
+5200C, 6200C).  Of course as HP releases new scanners this information
+may change.
+
+
+Requirements
+
+In order to get this running you'll need USB support in your kernel in
+addition to USB HP Scanner support.  Please refer to README.hp_scanner
+for issues pertaining to Linux USB and USB HP Scanner support.
+
+An installed version of SANE which is available from
+http://www.mostang.com/sane/.  Testing has been performed using
+version SANE-1.0.1.  For instructions on building and installing SANE,
+refer to the various README files within the distribution.
+
+
+Ok, so what do I do?
+
+NOTE: $INSTALL_DIR is the location where SANE was installed.  It may
+be /usr/local, /usr, /opt or somewhere else.  If you don't know, ask
+your system administrator.
+
+1) Make sure that you have the libsane-hp.* libraries under the
+$INSTALL_DIR/lib/sane/ directory.
+
+2) Under the directory $INSTALL_DIR/etc/sane.d/ edit the following
+files: dll.conf, hp.conf.
+
+  dll.conf:  Make sure that the 'hp' entry is present and uncommented.
+
+  hp.conf: This should contain two lines:
+
+    option connect-device
+    /dev/usbscanner
+
+3) You should now be able to use SANE (xscanimage or scanimage).
+
+Don't forget to read any relevant man pages regarding the usage of
+SANE.  If you have other entries uncommented in dll.conf, you my have
+to specify the device to (x)scanimage.  The xscanimage (1) man page
+has info on how to get 'The Gimp' to work with xscanimage.  Note that
+Gimp support must be compiled into SANE for it work.  If you are
+dealing with a RedHat system, you'll also need to install the
+gimp-devel rpm package.
+
+NOTE: Most of the time xscanimage will run without incident, then on
+the next invocation it'll core dump at different locations.  I don't
+know why yet and I don't have a work around either other than to try
+again.  But once you get it started, it'll scan without any problems
+(or at least it does for me).
+
+David /\/elson
+dnelson@jump.net
index 6c2ed4db94cdf67ab369f2fc8da6c3a8561fc46e..43311d0bb399e6e4045c049738a4d522c4fa891d 100644 (file)
@@ -597,9 +597,9 @@ int cpia_init_isoc(struct usb_cpia *cpia)
        /* First for desc. [0] */
        id = cpia->sbuf [0].isodesc;
        id->start_type = START_ASAP;
-       id->callback_frames = 1;        /* on every frame */
+       id->callback_frames = 10;       /* on every 10th frame */
        id->callback_fn = cpia_isoc_irq;
-       id->data = cpia->sbuf [0].data;
+       id->data = cpia->sbuf[0].data;
        id->buf_size = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
        for (fx = 0; fx < FRAMES_PER_DESC; fx++)
                id->frames [fx].frame_length = FRAME_SIZE_PER_DESC;
@@ -607,15 +607,15 @@ int cpia_init_isoc(struct usb_cpia *cpia)
        /* and the desc. [1] */
        id = cpia->sbuf [1].isodesc;
        id->start_type = 0;             /* will follow the first desc. */
-       id->callback_frames = 1;        /* on every frame */
+       id->callback_frames = 10;       /* on every 10th frame */
        id->callback_fn = cpia_isoc_irq;
-       id->data = cpia->sbuf [1].data;
+       id->data = cpia->sbuf[1].data;
        id->buf_size = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
        for (fx = 0; fx < FRAMES_PER_DESC; fx++)
                id->frames [fx].frame_length = FRAME_SIZE_PER_DESC;
 
-       usb_run_isoc (cpia->sbuf [0].isodesc, NULL);
-       usb_run_isoc (cpia->sbuf [1].isodesc, cpia->sbuf [0].isodesc);
+       usb_run_isoc (cpia->sbuf[0].isodesc, NULL);
+       usb_run_isoc (cpia->sbuf[1].isodesc, cpia->sbuf[0].isodesc);
 
 #if 0
        usb_schedule_isochronous(dev, cpia->sbuf[0].isodesc, NULL);
index 6fb9143098727212529431763d76b101591917ca..4596ec1599ffdc72754eb53ae054d41f81b44d33 100644 (file)
@@ -82,7 +82,7 @@
 
 #define SCRATCH_BUF_SIZE (STREAM_BUF_SIZE * 2)
 
-#define FRAMES_PER_DESC                500
+#define FRAMES_PER_DESC                10
 #define FRAME_SIZE_PER_DESC    960     /* Shouldn't be hardcoded */
 
 enum {
index e98423d09a875b0dd0abd8fe026ffeb7b2cf7b1a..d14c759e2cb7028a811f94fc8dae1550371ee8a3 100644 (file)
  *                  bulk reads.
  *                  Implemented EZUSB_SETINTERFACE, more sanity checks for EZUSB_BULK.
  *                  Preliminary ISO support
+ *   0.3  01.09.99  Async Bulk and ISO support
+ *   0.4  01.09.99
  *
  */
 
 /*****************************************************************************/
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/socket.h>
-#include <asm/uaccess.h>
 #include <linux/miscdevice.h>
 #include <linux/list.h>
 #include <linux/vmalloc.h>
 #include <linux/slab.h>
+#include <asm/spinlock.h>
+#include <asm/uaccess.h>
 
 #include "usb.h"
 #include "ezusb.h"
 static struct ezusb {
        struct semaphore mutex;
        struct usb_device *usbdev;
-       struct list_head iso;
+       struct list_head async_pending;
+       struct list_head async_completed;
+       wait_queue_head_t wait;
+       spinlock_t lock;
 } ezusb[NREZUSB];
 
-struct isodesc {
-       struct list_head isolist;
-       spinlock_t lock;
-       struct usb_device *usbdev;
-       unsigned int ep;
-       unsigned int pipe;
-       unsigned int pktsz;
-       unsigned int framesperint;
-       unsigned int rd, wr, buflen;
-       unsigned int flags;
-       unsigned int schedcnt, unschedcnt;
+struct async {
+       struct list_head asynclist;
+       struct ezusb *ez;
+       void *data;
+       unsigned dataorder;
+       void *userdata;
+       unsigned datalen;
+       union {
+               struct usb_isoc_desc *iso;
+               void *bulk;
+       } desc;
+       unsigned numframes; /* 0 means bulk, > 0 means iso */
+       struct ezusb_asynccompleted completed;
+};
 
-       void *hcbuf[2];
-       void *hcisodesc[2];
-       unsigned char *buf;
-};     
+/* --------------------------------------------------------------------- */
 
-#define ISOFLG_ACTIVE  (1<<0)
+extern inline unsigned ld2(unsigned int x)
+{
+        unsigned r = 0;
+        
+        if (x >= 0x10000) {
+                x >>= 16;
+                r += 16;
+        }
+        if (x >= 0x100) {
+                x >>= 8;
+                r += 8;
+        }
+        if (x >= 0x10) {
+                x >>= 4;
+                r += 4;
+        }
+        if (x >= 4) {
+                x >>= 2;
+                r += 2;
+        }
+        if (x >= 2)
+                r++;
+        return r;
+}
+
+/* --------------------------------------------------------------------- */
+
+extern __inline__ void async_removelist(struct async *as)
+{
+       struct ezusb *ez = as->ez;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ez->lock, flags);
+       list_del(&as->asynclist);
+       INIT_LIST_HEAD(&as->asynclist);
+       spin_unlock_irqrestore(&ez->lock, flags);
+}
+
+extern __inline__ void async_newpending(struct async *as)
+{
+       struct ezusb *ez = as->ez;
+       unsigned long flags;
+       
+       spin_lock_irqsave(&ez->lock, flags);
+       list_add_tail(&as->asynclist, &ez->async_pending);
+       spin_unlock_irqrestore(&ez->lock, flags);
+}
+
+extern __inline__ void async_movetocompleted(struct async *as)
+{
+       struct ezusb *ez = as->ez;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ez->lock, flags);
+       list_del(&as->asynclist);
+       list_add_tail(&as->asynclist, &ez->async_completed);
+       spin_unlock_irqrestore(&ez->lock, flags);
+}
+
+extern __inline__ struct async *async_getcompleted(struct ezusb *ez)
+{
+       unsigned long flags;
+       struct async *as = NULL;
+
+       spin_lock_irqsave(&ez->lock, flags);
+       if (!list_empty(&ez->async_completed)) {
+               as = list_entry(ez->async_completed.next, struct async, asynclist);
+               list_del(&as->asynclist);
+               INIT_LIST_HEAD(&as->asynclist);
+       }
+       spin_unlock_irqrestore(&ez->lock, flags);
+       return as;
+}
+
+extern __inline__ struct async *async_getpending(struct ezusb *ez, void *context)
+{
+       unsigned long flags;
+       struct async *as;
+       struct list_head *p;
+
+       spin_lock_irqsave(&ez->lock, flags);
+       for (p = ez->async_pending.next; p != &ez->async_pending; ) {
+               as = list_entry(p, struct async, asynclist);
+               p = p->next;
+               if (as->completed.context != context)
+                       continue;
+               list_del(&as->asynclist);
+               INIT_LIST_HEAD(&as->asynclist);
+               spin_unlock_irqrestore(&ez->lock, flags);
+               return as;
+       }
+       spin_unlock_irqrestore(&ez->lock, flags);
+       return NULL;
+}
+
+/* --------------------------------------------------------------------- */
+
+static int async_completed(int status, void *__buffer, int rval, void *dev_id)
+{
+       struct async *as = (struct async *)dev_id;
+       struct ezusb *ez = as->ez;
+       unsigned cnt;
+
+printk(KERN_DEBUG "ezusb: async_completed: status %d rval %d\n", status, rval);
+       as->completed.length = rval;
+       if (as->numframes > 0) {
+               as->completed.status = USB_ST_NOERROR;
+               for (cnt = 0; cnt < as->numframes; cnt++) {
+                       as->completed.isostat[cnt].status = as->desc.iso->frames[cnt].frame_status;
+                       as->completed.isostat[cnt].length = as->desc.iso->frames[cnt].frame_length;
+               }
+       } else
+               as->completed.status = status;
+       spin_lock(&ez->lock);
+       list_del(&as->asynclist);
+       list_add_tail(&as->asynclist, &ez->async_completed);
+       spin_unlock(&ez->lock);
+       wake_up(&ez->wait);
+       return 0;
+}
+
+static void remove_async(struct async *as)
+{
+       if (as->data && as->dataorder)
+               free_pages((unsigned long)as->data, as->dataorder);
+       if (as->numframes)
+               usb_free_isoc(as->desc.iso);
+       kfree(as);
+}
+
+static void kill_async(struct async *as)
+{
+       struct ezusb *ez = as->ez;
+
+       if (as->numframes)
+               /* ISO case */
+               usb_kill_isoc(as->desc.iso);
+       else
+               usb_terminate_bulk(ez->usbdev, as->desc.bulk);
+       as->completed.status = USB_ST_REMOVED;
+       async_movetocompleted(as);
+}
+
+static void destroy_all_async(struct ezusb *ez)
+{
+       struct async *as;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ez->lock, flags);
+       if (!list_empty(&ez->async_completed)) {
+               as = list_entry(ez->async_pending.next, struct async, asynclist);
+               list_del(&as->asynclist);
+               INIT_LIST_HEAD(&as->asynclist);
+               spin_unlock_irqrestore(&ez->lock, flags);
+               kill_async(as);
+               spin_lock_irqsave(&ez->lock, flags);
+       }
+       spin_unlock_irqrestore(&ez->lock, flags);
+       while ((as = async_getcompleted(ez)))
+               remove_async(as);
+}
 
 /* --------------------------------------------------------------------- */
 
@@ -216,439 +383,504 @@ static int ezusb_open(struct inode *inode, struct file *file)
        up(&ez->mutex);
        file->f_pos = 0;
        file->private_data = ez;
+       MOD_INC_USE_COUNT;
        return 0;
 }
 
 static int ezusb_release(struct inode *inode, struct file *file)
 {
        struct ezusb *ez = (struct ezusb *)file->private_data;
+
+       down(&ez->mutex);
+       destroy_all_async(ez);
+       up(&ez->mutex);
+       MOD_DEC_USE_COUNT;
        return 0;
 }
 
-static void iso_schedrcv(struct isodesc *isodesc)
+static int ezusb_control(struct usb_device *usbdev, unsigned char requesttype,
+                        unsigned char request, unsigned short value, 
+                        unsigned short index, unsigned short length,
+                        void *data)
 {
-       unsigned diff;
-
-       if (!(isodesc->flags & ISOFLG_ACTIVE))
-               return;
-       diff = (isodesc->buflen - 1 + isodesc->rd - isodesc->wr) % isodesc->buflen;
-       if (diff < isodesc->framesperint * isodesc->pktsz)
-               return;
-       for (;;) {
-               diff = (isodesc->schedcnt - isodesc->unschedcnt) & 3;
-               if (diff >= 2)
-                       return;
-               usb_schedule_isochronous(isodesc->usbdev, isodesc->hcisodesc[isodesc->schedcnt & 1],
-                                        diff ? isodesc->hcisodesc[(isodesc->schedcnt - 1) & 1] : NULL);
-               isodesc->schedcnt++;
+       unsigned char *tbuf = NULL;
+       unsigned int pipe;
+       int i;
+
+       if (length > PAGE_SIZE)
+               return -EINVAL;
+       /* __range_ok is broken; 
+          with unsigned short size, it gave
+          addl %si,%edx ; sbbl %ecx,%ecx; cmpl %edx,12(%eax); sbbl $0,%ecx
+       */
+       if (requesttype & 0x80) {
+               pipe = usb_rcvctrlpipe(usbdev, 0);
+               if (length > 0 && !access_ok(VERIFY_WRITE, data, (unsigned int)length))
+                       return -EFAULT;
+       } else
+               pipe = usb_sndctrlpipe(usbdev, 0);
+       if (length > 0) {
+               if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))
+                       return -ENOMEM;
+               if (!(requesttype & 0x80)) {
+                       if (copy_from_user(tbuf, data, length)) {
+                               free_page((unsigned long)tbuf);
+                               return -EFAULT;
+                       }
+               }
        }
+       i = usb_control_msg(usbdev, pipe, request, requesttype, value, index, tbuf, length);
+       if (i) {
+               if (length > 0)
+                       free_page((unsigned long)tbuf);
+               printk(KERN_WARNING "ezusb: EZUSB_CONTROL failed rqt %u rq %u len %u ret %d\n", 
+                      requesttype, request, length, i);
+               return -ENXIO;
+       }
+       if (requesttype & 0x80 && length > 0 && copy_to_user(data, tbuf, length))
+               i = -EFAULT;
+       if (length > 0)
+               free_page((unsigned long)tbuf);
+       return i;
 }
 
-static void iso_schedsnd(struct isodesc *isodesc)
+static int ezusb_bulk(struct usb_device *usbdev, unsigned int ep, unsigned int length, void *data)
 {
-       unsigned diff, bcnt, x;
-       unsigned char *p1, *p2;
-
-       if (!(isodesc->flags & ISOFLG_ACTIVE))
-               return;
-       for (;;) {
-               diff = (isodesc->schedcnt - isodesc->unschedcnt) & 3;
-               if (diff >= 2)
-                       return;
-               bcnt = (isodesc->buflen - isodesc->rd + isodesc->wr) % isodesc->buflen;
-               if (bcnt < isodesc->framesperint * isodesc->pktsz)
-                       return;
-               p2 = isodesc->hcbuf[isodesc->schedcnt & 1];
-               for (bcnt = 0; bcnt < isodesc->framesperint; bcnt++) {
-                       p1 = isodesc->buf + isodesc->rd;
-                       if (isodesc->rd + isodesc->pktsz > isodesc->buflen) {
-                               x = isodesc->buflen - isodesc->rd;
-                               memcpy(p2, p1, x);
-                               memcpy(p2+x, isodesc->buf, isodesc->pktsz - x);
-                       } else
-                               memcpy(p2, p1, isodesc->pktsz);
-                       isodesc->rd = (isodesc->rd + isodesc->pktsz) % isodesc->buflen;
-                       p2 += isodesc->pktsz;
-                       if (((unsigned long)p2 ^ ((unsigned long)p2 + isodesc->pktsz - 1)) & (~(PAGE_SIZE - 1)))
-                               p2 = (void *)(((unsigned long)p2 + PAGE_SIZE - 1) & (~(PAGE_SIZE - 1)));
-               }
-               usb_schedule_isochronous(isodesc->usbdev, isodesc->hcisodesc[isodesc->schedcnt & 1],
-                                        diff ? isodesc->hcisodesc[(isodesc->schedcnt - 1) & 1] : NULL);
-               isodesc->schedcnt++;
+       unsigned char *tbuf = NULL;
+       unsigned int pipe;
+       unsigned long len2 = 0;
+       int ret = 0;
+
+       if (length > PAGE_SIZE)
+               return -EINVAL;
+       if ((ep & ~0x80) >= 16)
+               return -EINVAL;
+       if (ep & 0x80) {
+               pipe = usb_rcvbulkpipe(usbdev, ep & 0x7f);
+               if (length > 0 && !access_ok(VERIFY_WRITE, data, length))
+                       return -EFAULT;
+       } else
+               pipe = usb_sndbulkpipe(usbdev, ep & 0x7f);
+       if (!usb_maxpacket(usbdev, pipe, !(ep & 0x80)))
+               return -EINVAL;
+       if (length > 0) {
+               if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))
+                       return -ENOMEM;
+               if (!(ep & 0x80)) {
+                       if (copy_from_user(tbuf, data, length)) {
+                               free_page((unsigned long)tbuf);
+                               return -EFAULT;
+                       }
+               }
+       }
+       ret = usbdev->bus->op->bulk_msg(usbdev, pipe, tbuf, length, &len2);
+       if (ret) {
+               if (length > 0)
+                       free_page((unsigned long)tbuf);
+               printk(KERN_WARNING "ezusb: EZUSB_BULK failed ep 0x%x len %u ret %d\n", 
+                      ep, length, ret);
+               return -ENXIO;
        }
+       if (len2 > length)
+               len2 = length;
+       ret = len2;
+       if (ep & 0x80 && len2 > 0 && copy_to_user(data, tbuf, len2))
+               ret = -EFAULT;
+       if (length > 0)
+               free_page((unsigned long)tbuf);
+       return ret;
 }
 
-static int ezusb_isorcv_irq(int status, void *__buffer, int __len, void *dev_id)
+static int ezusb_resetep(struct usb_device *usbdev, unsigned int ep)
 {
-       struct isodesc *isodesc = (struct isodesc *)dev_id;
-       unsigned int len, len2;
-       unsigned char *p1;
-
-       spin_lock(&isodesc->lock);
-       usb_unschedule_isochronous(isodesc->usbdev, isodesc->hcisodesc[isodesc->unschedcnt & 1]);
-       len = usb_compress_isochronous(isodesc->usbdev, isodesc->hcisodesc[isodesc->unschedcnt & 1]);
-       printk(KERN_DEBUG "ezusb_isorcv_irq: %u bytes recvd\n", len);
-       p1 = isodesc->hcbuf[isodesc->unschedcnt & 1];
-       while (len > 0) {
-               len2 = (isodesc->buflen - 1 + isodesc->rd - isodesc->wr) % isodesc->buflen;
-               if (!len2)
-                       break;
-               if (isodesc->wr + len2 > isodesc->buflen)
-                       len2 = isodesc->buflen - isodesc->wr;
-               if (len2 > len)
-                       len2 = len;
-               memcpy(isodesc->buf + isodesc->wr, p1, len2);
-               isodesc->wr = (isodesc->wr + len2) % isodesc->buflen;
-               p1 += len2;
-               len -= len2;
-       }
-       isodesc->unschedcnt++;
-       iso_schedrcv(isodesc);
-       spin_unlock(&isodesc->lock);
-       return 1;
+       if ((ep & ~0x80) >= 16)
+               return -EINVAL;
+       usb_settoggle(usbdev, ep & 0xf, !(ep & 0x80), 0);
+       return 0;
+}
+
+static int ezusb_setinterface(struct usb_device *usbdev, unsigned int interface, unsigned int altsetting)
+{
+       if (usb_set_interface(usbdev, interface, altsetting))
+               return -EINVAL;
+       return 0;
 }
 
-static int ezusb_isosnd_irq(int status, void *__buffer, int len, void *dev_id)
+static int ezusb_setconfiguration(struct usb_device *usbdev, unsigned int config)
 {
-       struct isodesc *isodesc = (struct isodesc *)dev_id;
-
-       spin_lock(&isodesc->lock);
-       usb_unschedule_isochronous(isodesc->usbdev, isodesc->hcisodesc[isodesc->unschedcnt & 1]);
-       isodesc->unschedcnt++;
-       iso_schedsnd(isodesc);
-       spin_unlock(&isodesc->lock);
-       return 1;
+       if (usb_set_configuration(usbdev, config))
+               return -EINVAL;
+       return 0;
 }
 
-static struct isodesc *findiso(struct ezusb *ez, unsigned int ep)
+static int ezusb_requestbulk(struct ezusb *ez, struct ezusb_asyncbulk *ab)
 {
-       struct list_head *head = &ez->iso;
-       struct list_head *tmp = head->next;
-       struct isodesc *id;
+       struct async *as = NULL;
+       unsigned int pipe;
+
+       if (ab->len > PAGE_SIZE)
+               return -EINVAL;
+       if ((ab->ep & ~0x80) >= 16)
+               return -EINVAL;
+       if (ab->ep & 0x80) {
+               pipe = usb_rcvbulkpipe(ez->usbdev, ab->ep & 0x7f);
+               if (ab->len > 0 && !access_ok(VERIFY_WRITE, ab->data, ab->len))
+                       return -EFAULT;
+       } else
+               pipe = usb_sndbulkpipe(ez->usbdev, ab->ep & 0x7f);
+       if (!usb_maxpacket(ez->usbdev, pipe, !(ab->ep & 0x80)))
+               return -EINVAL;
+       if (!(as = kmalloc(sizeof(struct async), GFP_KERNEL)))
+               return -ENOMEM;
+       INIT_LIST_HEAD(&as->asynclist);
+       as->ez = ez;
+       as->userdata = ab->data;
+       as->numframes = 0;
+       as->data = 0;
+       as->dataorder = 0;
+       as->datalen = ab->len;
+       as->completed.context = ab->context;
+       if (ab->len > 0) {
+               as->dataorder = 1;
+               if (!(as->data = (unsigned char *)__get_free_page(GFP_KERNEL))) {
+                       kfree(as);
+                       return -ENOMEM;
+               }
+               if (!(ab->ep & 0x80)) {
+                       if (copy_from_user(as->data, ab->data, ab->len))
+                               goto err_fault;
+                       as->datalen = 0; /* no need to copy back at completion */
+               }
+       }
+       async_newpending(as);
+       if (!(as->desc.bulk = usb_request_bulk(ez->usbdev, pipe, async_completed, as->data, ab->len, as))) {
+               async_removelist(as);
+               goto err_inval;
+       }
+       return 0;
 
-       while (tmp != head) {
-               id = list_entry(tmp, struct isodesc, isolist);
-               if (id->ep == ep)
-                       return id;
-               tmp = tmp->next;
+ err_fault:
+       if (as) {
+               if (as->data)
+                       free_page((unsigned long)as->data);
+               kfree(as);
        }
-       return NULL;
+       return -EFAULT;
+
+ err_inval:
+       if (as) {
+               if (as->data)
+                       free_page((unsigned long)as->data);
+               kfree(as);
+       }
+       return -EINVAL;
+}
+
+static int ezusb_requestiso(struct ezusb *ez, struct ezusb_asynciso *ai, unsigned char *cmd)
+{
+       struct async *as;
+       unsigned int maxpkt, pipe;
+       unsigned int dsize, order, assize, j;
+       int i;
+
+       if ((ai->ep & ~0x80) >= 16 || ai->framecnt < 1 || ai->framecnt > 128)
+               return -EINVAL;
+       if (ai->ep & 0x80)
+               pipe = usb_rcvisocpipe(ez->usbdev, ai->ep & 0x7f);
+       else
+               pipe = usb_sndisocpipe(ez->usbdev, ai->ep & 0x7f);
+       if (!(maxpkt = usb_maxpacket(ez->usbdev, pipe, !(ai->ep & 0x80))))
+               return -EINVAL;
+       dsize = maxpkt * ai->framecnt;
+       if (dsize > 65536) 
+               return -EINVAL;
+       order = ld2(dsize >> PAGE_SHIFT);
+       if (dsize > (PAGE_SIZE << order))
+               order++;
+       if (ai->ep & 0x80)
+               if (dsize > 0 && !access_ok(VERIFY_WRITE, ai->data, dsize))
+                       return -EFAULT;
+       assize = sizeof(struct async) + ai->framecnt * sizeof(struct ezusb_isoframestat);
+       if (!(as = kmalloc(assize, GFP_KERNEL)))
+               return -ENOMEM;
+       memset(as, 0, assize);
+       INIT_LIST_HEAD(&as->asynclist);
+       as->ez = ez;
+       as->userdata = ai->data;
+       as->numframes = ai->framecnt;
+       as->data = 0;
+       as->dataorder = order;
+       as->datalen = dsize;
+       as->completed.context = ai->context;
+       as->desc.iso = NULL;
+       if (dsize > 0) {
+               if (!(as->data = (unsigned char *)__get_free_pages(GFP_KERNEL, order))) {
+                       kfree(as);
+                       return -ENOMEM;
+               }
+               if (!(ai->ep & 0x80)) {
+                       if (copy_from_user(as->data, ai->data, dsize))
+                               goto err_fault;
+                       as->datalen = 0; /* no need to copy back at completion */
+               }
+       }
+       if ((i = usb_init_isoc(ez->usbdev, pipe, ai->framecnt, as, &as->desc.iso))) {
+               printk(KERN_DEBUG "ezusb: usb_init_isoc error %d\n", i);
+               goto err_inval;
+       }
+       as->desc.iso->start_type = START_ASAP;
+       as->desc.iso->callback_frames = 0;
+       as->desc.iso->callback_fn = async_completed;
+       as->desc.iso->data = as->data;
+       as->desc.iso->buf_size = dsize;
+       for (j = 0; j < ai->framecnt; j++) {
+               if (get_user(i, (int *)(cmd + j * sizeof(struct ezusb_isoframestat)))) {
+                       usb_free_isoc(as->desc.iso);
+                       kfree(as);
+                       return -EFAULT;
+               }
+               if (i < 0)
+                       i = 0;
+               as->desc.iso->frames[j].frame_length = i;
+       }
+               async_newpending(as);
+       if ((i = usb_run_isoc(as->desc.iso, NULL))) {
+               printk(KERN_DEBUG "ezusb: usb_run_isoc error %d\n", i);
+               async_removelist(as);
+               goto err_inval;
+       }
+       return 0;
+
+ err_fault:
+       if (as) {
+               if (as->desc.iso)
+                       usb_free_isoc(as->desc.iso);
+               if (as->data)
+                       free_page((unsigned long)as->data);
+               kfree(as);
+       }
+       return -EFAULT;
+
+ err_inval:
+       if (as) {
+               if (as->desc.iso)
+                       usb_free_isoc(as->desc.iso);
+               if (as->data)
+                       free_page((unsigned long)as->data);
+               kfree(as);
+       }
+       return -EINVAL;
+}
+
+static int ezusb_terminateasync(struct ezusb *ez, void *context)
+{
+       struct async *as;
+       int ret = 0;
+
+       while ((as = async_getpending(ez, context))) {
+               kill_async(as);
+               ret++;
+       }
+       return ret;
+}
+
+static int ezusb_asynccompl(struct async *as, void *arg)
+{
+       if (as->datalen > 0) {
+               if (copy_to_user(as->userdata, as->data, as->datalen)) {
+                       remove_async(as);
+                       return -EFAULT;
+               }
+       }
+       if (copy_to_user(arg, &as->completed, 
+                        sizeof(struct ezusb_asynccompleted) + 
+                        as->numframes * sizeof(struct ezusb_isoframestat))) {
+               remove_async(as);
+               return -EFAULT;
+       }
+       remove_async(as);
+       return 0;
 }
 
 static int ezusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
        struct ezusb *ez = (struct ezusb *)file->private_data;
+        DECLARE_WAITQUEUE(wait, current);
+       struct usb_proc_ctrltransfer pctrl;
+       struct usb_proc_bulktransfer pbulk;
+       struct usb_proc_setinterface psetintf;
        struct ezusb_ctrltransfer ctrl;
        struct ezusb_bulktransfer bulk;
        struct ezusb_setinterface setintf;
-       unsigned int len1, ep, pipe, cnt;
-       unsigned long len2;
-       unsigned char tbuf[1024];
-       int i;
-       struct ezusb_isotransfer isot;
-       struct ezusb_isodata isod;
-       struct isodesc *isodesc;
-       usb_device_irq isocompl;
-       unsigned long flags;
-       unsigned char *p1, *p2;
+       struct ezusb_asyncbulk abulk;
+       struct ezusb_asynciso aiso;
+       struct async *as;
+       void *context;
+       unsigned int ep, cfg;
+       int i, ret = 0;
 
+       down(&ez->mutex);
+       if (!ez->usbdev) {
+               up(&ez->mutex);
+               return -EIO;
+       }
        switch (cmd) {
+       case USB_PROC_CONTROL:
+               if (copy_from_user(&pctrl, (void *)arg, sizeof(pctrl))) {
+                       ret = -EFAULT;
+                       break;
+               }
+               ret = ezusb_control(ez->usbdev, pctrl.requesttype, pctrl.request, 
+                                   pctrl.value, pctrl.index, pctrl.length, pctrl.data);
+               break;
+
+       case USB_PROC_BULK:
+               if (copy_from_user(&pbulk, (void *)arg, sizeof(pbulk))) {
+                       ret = -EFAULT;
+                       break;
+               }
+               ret = ezusb_bulk(ez->usbdev, pbulk.ep, pbulk.len, pbulk.data);
+               break;
+
+       case USB_PROC_RESETEP:
+               if (get_user(ep, (unsigned int *)arg)) {
+                       ret = -EFAULT;
+                       break;
+               }
+               ret = ezusb_resetep(ez->usbdev, ep);
+               break;
+       
+       case USB_PROC_SETINTERFACE:
+               if (copy_from_user(&psetintf, (void *)arg, sizeof(psetintf))) {
+                       ret = -EFAULT;
+                       break;
+               }
+               ret = ezusb_setinterface(ez->usbdev, psetintf.interface, psetintf.altsetting);
+               break;
+
+       case USB_PROC_SETCONFIGURATION:
+               if (get_user(cfg, (unsigned int *)arg)) {
+                       ret = -EFAULT;
+                       break;
+               }
+               ret = ezusb_setconfiguration(ez->usbdev, cfg);
+               break;
+
        case EZUSB_CONTROL:
-               copy_from_user_ret(&ctrl, (void *)arg, sizeof(ctrl), -EFAULT);
-               if (ctrl.dlen > sizeof(tbuf) || ctrl.dlen > 1024)
-                       return -EINVAL;
-               if (ctrl.requesttype & 0x80) {
-                       if (ctrl.dlen && !access_ok(VERIFY_WRITE, ctrl.data, ctrl.dlen))
-                               return -EINVAL;
-                       down(&ez->mutex);
-                       if (!ez->usbdev) {
-                               up(&ez->mutex);
-                               return -EIO;
-                       }
-                       i = ez->usbdev->bus->op->control_msg(ez->usbdev, usb_rcvctrlpipe(ez->usbdev, 0),
-                                                            (devrequest *)&ctrl, tbuf, ctrl.dlen);
-                       up(&ez->mutex);
-                       if (!i && ctrl.dlen) {
-                               copy_to_user_ret(ctrl.data, tbuf, ctrl.dlen, -EFAULT);
-                       }
-               } else {
-                       if (ctrl.dlen) {
-                               copy_from_user_ret(tbuf, ctrl.data, ctrl.dlen, -EFAULT);
-                       }
-                       down(&ez->mutex);
-                       if (!ez->usbdev) {
-                               up(&ez->mutex);
-                               return -EIO;
-                       }
-                       i = ez->usbdev->bus->op->control_msg(ez->usbdev, usb_sndctrlpipe(ez->usbdev, 0),
-                                                            (devrequest *)&ctrl, tbuf, ctrl.dlen);
-                       up(&ez->mutex);
+               if (copy_from_user(&ctrl, (void *)arg, sizeof(ctrl))) {
+                       ret = -EFAULT;
+                       break;
                }
-               if (i) {
-                       printk(KERN_WARNING "ezusb: EZUSB_CONTROL failed rqt %u rq %u len %u ret %d\n", 
-                              ctrl.requesttype, ctrl.request, ctrl.length, i);
-                       return -ENXIO;
+               if (ctrl.dlen != ctrl.length) {
+                       ret = -EINVAL;
+                       break;
                }
-               return 0;
+               ret = ezusb_control(ez->usbdev, ctrl.requesttype, ctrl.request, 
+                                   ctrl.value, ctrl.index, ctrl.length, ctrl.data);
+               break;
 
        case EZUSB_BULK:
-               copy_from_user_ret(&bulk, (void *)arg, sizeof(bulk), -EFAULT);
-               if (bulk.ep & 0x80)
-                       pipe = usb_rcvbulkpipe(ez->usbdev, bulk.ep & 0x7f);
-               else
-                       pipe = usb_sndbulkpipe(ez->usbdev, bulk.ep & 0x7f);
-               if (!usb_maxpacket(ez->usbdev, pipe, !(bulk.ep & 0x80)))
-                       return -EINVAL;
-               len1 = bulk.len;
-               if (len1 > sizeof(tbuf))
-                       len1 = sizeof(tbuf);
-               if (bulk.ep & 0x80) {
-                       if (len1 && !access_ok(VERIFY_WRITE, bulk.data, len1))
-                               return -EINVAL;
-                       down(&ez->mutex);
-                       if (!ez->usbdev) {
-                               up(&ez->mutex);
-                               return -EIO;
-                       }
-                       i = ez->usbdev->bus->op->bulk_msg(ez->usbdev, pipe, tbuf, len1, &len2);
-                       up(&ez->mutex);
-                       if (!i && len2) {
-                               copy_to_user_ret(bulk.data, tbuf, len2, -EFAULT);
-                       }
-               } else {
-                       if (len1) {
-                               copy_from_user_ret(tbuf, bulk.data, len1, -EFAULT);
-                       }
-                       down(&ez->mutex);
-                       if (!ez->usbdev) {
-                               up(&ez->mutex);
-                               return -EIO;
-                       }
-                       i = ez->usbdev->bus->op->bulk_msg(ez->usbdev, pipe, tbuf, len1, &len2);
-                       up(&ez->mutex);
-               }
-               if (i) {
-                       printk(KERN_WARNING "ezusb: EZUSB_BULK failed ep 0x%x len %u ret %d\n", 
-                              bulk.ep, bulk.len, i);
-                       return -ENXIO;
+               if (copy_from_user(&bulk, (void *)arg, sizeof(bulk))) {
+                       ret = -EFAULT;
+                       break;
                }
-               return len2;
+               ret = ezusb_bulk(ez->usbdev, bulk.ep, bulk.len, bulk.data);
+               break;
 
        case EZUSB_RESETEP:
-               get_user_ret(ep, (unsigned int *)arg, -EFAULT);
-               if ((ep & ~0x80) >= 16)
-                       return -EINVAL;
-               usb_settoggle(ez->usbdev, ep & 0xf, !(ep & 0x80), 0);
-               return 0;
-
+               if (get_user(ep, (unsigned int *)arg)) {
+                       ret = -EFAULT;
+                       break;
+               }
+               ret = ezusb_resetep(ez->usbdev, ep);
+               break;
+       
        case EZUSB_SETINTERFACE:
-               copy_from_user_ret(&setintf, (void *)arg, sizeof(setintf), -EFAULT);
-               if (usb_set_interface(ez->usbdev, setintf.interface, setintf.altsetting))
-                       return -EINVAL;
-               return 0;
-
-       case EZUSB_STARTISO:
-               copy_from_user_ret(&isot, (void *)arg, sizeof(isot), -EFAULT);
-               len1 = isot.framesperint * isot.pktsz;
-               if (len1 > PAGE_SIZE) {
-                       len1 = PAGE_SIZE / isot.pktsz;
-                       len1 = PAGE_SIZE * ((isot.framesperint + len1 - 1) / len1);
-               }
-               len2 = (isot.pktsz * 1000 + PAGE_SIZE - 1) & (PAGE_SIZE-1);
-               if (len2 > 32*PAGE_SIZE)
-                       len2 = PAGE_SIZE;
-               if ((isot.ep & ~0x80) >= 16 || isot.pktsz < 1 || isot.pktsz > 1023 ||
-                   isot.framesperint < 1 || isot.framesperint > 1000 ||
-                   len1 > 4*PAGE_SIZE)
-                       return -EINVAL;
-               down(&ez->mutex);
-               if (!ez->usbdev) {
-                       up(&ez->mutex);
-                       return -EIO;
+               if (copy_from_user(&setintf, (void *)arg, sizeof(setintf))) {
+                       ret = -EFAULT;
+                       break;
+               }
+               ret = ezusb_setinterface(ez->usbdev, setintf.interface, setintf.altsetting);
+               break;
+
+       case EZUSB_SETCONFIGURATION:
+               if (get_user(cfg, (unsigned int *)arg)) {
+                       ret = -EFAULT;
+                       break;
                }
-               if (findiso(ez, isod.ep)) {
+               ret = ezusb_setconfiguration(ez->usbdev, cfg);
+               break;
+
+       case EZUSB_ASYNCCOMPLETED:
+               current->state = TASK_INTERRUPTIBLE;
+               add_wait_queue(&ez->wait, &wait);
+               for (;;) {
+                       if (!ez->usbdev)
+                               break;
+                       if ((as = async_getcompleted(ez)))
+                               break;
+                       if (signal_pending(current))
+                               break;
                        up(&ez->mutex);
-                       return -EBUSY;
+                       schedule();
+                       down(&ez->mutex);
                }
-               if (isot.ep & 0x80) {
-                       pipe = usb_rcvisocpipe(ez->usbdev, isot.ep & 15);
-                       isocompl = ezusb_isorcv_irq;
-               } else {
-                       pipe = usb_sndisocpipe(ez->usbdev, isot.ep & 15);
-                       isocompl = ezusb_isosnd_irq;
+               remove_wait_queue(&ez->wait, &wait);
+               current->state = TASK_RUNNING;
+               if (as) {
+                       ret = ezusb_asynccompl(as, (void *)arg);
+                       break;
                }
-               if (!(isodesc = kmalloc(sizeof(struct isodesc), GFP_KERNEL))) {
-                       up(&ez->mutex);
-                       return -ENOMEM;
+               if (signal_pending(current)) {
+                       ret = -EINTR;
+                       break;
                }
-               memset(isodesc, 0, sizeof(struct isodesc));
-               INIT_LIST_HEAD(&isodesc->isolist);
-               spin_lock_init(&isodesc->lock);
-               isodesc->usbdev = ez->usbdev;
-               isodesc->ep = isot.ep;
-               isodesc->pktsz = isot.pktsz;
-               isodesc->framesperint = isot.framesperint;
-               isodesc->buflen = len2;
-               if (!(isodesc->hcbuf[0] = kmalloc(len1, GFP_KERNEL)) ||
-                   !(isodesc->hcbuf[1] = kmalloc(len1, GFP_KERNEL)))
-                       goto startisomemerr;
-               if (!(isodesc->hcisodesc[0] = usb_allocate_isochronous(ez->usbdev, pipe, isodesc->hcbuf[0],
-                                                                      len1, isodesc->pktsz, isocompl, isodesc)) ||
-                   !(isodesc->hcisodesc[1] = usb_allocate_isochronous(ez->usbdev, pipe, isodesc->hcbuf[1],
-                                                                      len1, isodesc->pktsz, isocompl, isodesc)))
-                       goto startisomemerr;
-               if (!(isodesc->buf = vmalloc(isodesc->buflen)))
-                       goto startisomemerr;
-               up(&ez->mutex);
-               return 0;
-
-       startisomemerr:
-               if (isodesc->hcisodesc[0])
-                       usb_delete_isochronous(ez->usbdev, isodesc->hcisodesc[0]);
-               if (isodesc->hcisodesc[1])
-                       usb_delete_isochronous(ez->usbdev, isodesc->hcisodesc[1]);
-               if (isodesc->hcbuf[0])
-                       kfree(isodesc->hcbuf[0]);
-               if (isodesc->hcbuf[1])
-                       kfree(isodesc->hcbuf[1]);
-               if (isodesc->buf)
-                       vfree(isodesc->buf);
-               up(&ez->mutex);
-               return -ENOMEM;
+               ret = -EIO;
+               break;
 
-       case EZUSB_STOPISO:
-               get_user_ret(ep, (unsigned int *)arg, -EFAULT);
-               if ((ep & ~0x80) >= 16)
-                       return -EINVAL;
-               down(&ez->mutex);
-               if (!ez->usbdev) {
-                       up(&ez->mutex);
-                       return -EIO;
+       case EZUSB_ASYNCCOMPLETEDNB:
+               if ((as = async_getcompleted(ez))) {
+                       ret = ezusb_asynccompl(as, (void *)arg);
+                       break;
                }
-               if (!(isodesc = findiso(ez, ep))) {
-                       up(&ez->mutex);
-                       return -EINVAL;
-               }
-               list_del(&isodesc->isolist);
-               usb_delete_isochronous(ez->usbdev, isodesc->hcisodesc[0]);
-               usb_delete_isochronous(ez->usbdev, isodesc->hcisodesc[1]);
-               kfree(isodesc->hcbuf[0]);
-               kfree(isodesc->hcbuf[1]);
-               vfree(isodesc->buf);
-               up(&ez->mutex);
-               return 0;
-
-       case EZUSB_ISODATA:
-               copy_from_user_ret(&isod, (void *)arg, sizeof(isod), -EFAULT);
-               if ((isod.ep & ~0x80) >= 16)
-                       return -EINVAL;
-               if (isod.size)
-                       if (!access_ok((isod.ep & 0x80) ? VERIFY_WRITE : VERIFY_READ, isod.data, isod.size))
-                               return -EFAULT;
-               down(&ez->mutex);
-               if (!ez->usbdev) {
-                       up(&ez->mutex);
-                       return -EIO;
+               ret = -EAGAIN;
+               break;
+
+       case EZUSB_REQUESTBULK:
+               if (copy_from_user(&abulk, (void *)arg, sizeof(abulk))) {
+                       ret = -EFAULT;
+                       break;
                }
-               if (!(isodesc = findiso(ez, ep))) {
-                       up(&ez->mutex);
-                       return -EINVAL;
-               }
-               if (isod.ep & 0x80) {
-                       cnt = 0;
-                       p1 = isod.data;
-                       while (cnt < isod.size) {
-                               spin_lock_irqsave(&isodesc->lock, flags);
-                               p2 = isodesc->buf + isodesc->rd;
-                               len2 = (isodesc->rd >= isodesc->wr) ? isodesc->buflen : isodesc->wr;
-                               len2 -= isodesc->rd;
-                               spin_unlock_irqrestore(&isodesc->lock, flags);
-                               if (len2 <= 0)
-                                       break;
-                               if (len2 >= isod.size - cnt)
-                                       len2 = isod.size - cnt;
-                               if (__copy_to_user(p1, p2, len2)) {
-                                       up(&ez->mutex);
-                                       return -EFAULT;
-                               }
-                               p1 += len2;
-                               cnt += len2;
-                               spin_lock_irqsave(&isodesc->lock, flags);
-                               isodesc->rd = (isodesc->rd + len2) % isodesc->buflen;
-                               spin_unlock_irqrestore(&isodesc->lock, flags);
-                       }
-                       isod.size = cnt;
-                       iso_schedrcv(isodesc);
-               } else {
-                       cnt = 0;
-                       p1 = isod.data;
-                       while (cnt < isod.size) {
-                               spin_lock_irqsave(&isodesc->lock, flags);
-                               p2 = isodesc->buf + isodesc->wr;
-                               len2 = (isodesc->buflen - 1 + isodesc->rd - isodesc->wr) % isodesc->buflen;
-                               if (isodesc->wr + len2 > isodesc->buflen)
-                                       len2 = isodesc->buflen - isodesc->wr;
-                               spin_unlock_irqrestore(&isodesc->lock, flags);
-                               if (len2 <= 0)
-                                       break;
-                               if (len2 >= isod.size - cnt)
-                                       len2 = isod.size - cnt;
-                               if (__copy_from_user(p2, p1, len2)) {
-                                       up(&ez->mutex);
-                                       return -EFAULT;
-                               }
-                               p1 += len2;
-                               cnt += len2;
-                               spin_lock_irqsave(&isodesc->lock, flags);
-                               isodesc->wr = (isodesc->wr + len2) % isodesc->buflen;
-                               spin_unlock_irqrestore(&isodesc->lock, flags);
-                       }
-                       isod.size = cnt;
-                       iso_schedsnd(isodesc);
+               ret = ezusb_requestbulk(ez, &abulk);
+               break;  
+
+       case EZUSB_REQUESTISO:
+               if (copy_from_user(&aiso, (void *)arg, sizeof(aiso))) {
+                       ret = -EFAULT;
+                       break;
                }
-               spin_lock_irqsave(&isodesc->lock, flags);
-               isod.bufqueued = (isodesc->buflen + isodesc->wr - isodesc->rd) % isodesc->buflen;
-               isod.buffree = (isodesc->buflen - 1 + isodesc->rd - isodesc->wr) % isodesc->buflen;
-               spin_unlock_irqrestore(&isodesc->lock, flags);
-               up(&ez->mutex);
-               copy_to_user_ret((void *)arg, &isod, sizeof(isod), -EFAULT);
-               return 0;
-
-       case EZUSB_PAUSEISO:
-               get_user_ret(ep, (unsigned int *)arg, -EFAULT);
-               if ((ep & ~0x80) >= 16)
-                       return -EINVAL;
-               if (!(isodesc = findiso(ez, ep)))
-                       return -EINVAL;
-               spin_lock_irqsave(&isodesc->lock, flags);
-               isodesc->flags &= ~ISOFLG_ACTIVE;
-               spin_unlock_irqrestore(&isodesc->lock, flags);
-               return 0;
-
-       case EZUSB_RESUMEISO:
-               get_user_ret(ep, (unsigned int *)arg, -EFAULT);
-               if ((ep & ~0x80) >= 16)
-                       return -EINVAL;
-               down(&ez->mutex);
-               if (!ez->usbdev) {
-                       up(&ez->mutex);
-                       return -EIO;
+               ret = ezusb_requestiso(ez, &aiso, ((unsigned char *)arg)+sizeof(aiso));
+               break;
+
+       case EZUSB_TERMINATEASYNC:
+               if (get_user(context, (void **)arg)) {
+                       ret = -EFAULT;
+                       break;
                }
-               if (!(isodesc = findiso(ez, ep))) {
-                       up(&ez->mutex);
-                       return -EINVAL;
-               }
-               spin_lock_irqsave(&isodesc->lock, flags);
-               isodesc->flags |= ISOFLG_ACTIVE;
-               if (isot.ep & 0x80)
-                       iso_schedrcv(isodesc);
-               else
-                       iso_schedsnd(isodesc);
-               spin_unlock_irqrestore(&isodesc->lock, flags);
-               up(&ez->mutex);
-               return 0;
+               ret = ezusb_terminateasync(ez, context);
+               break;
+
+       case EZUSB_GETFRAMENUMBER:
+               i = usb_get_current_frame_number(ez->usbdev);
+               ret = put_user(i, (int *)arg);
+               break;
+
+       default:
+               ret = -ENOIOCTLCMD;
+               break;
        }
-       return -ENOIOCTLCMD;
+       up(&ez->mutex);
+       return ret;
 }
 
 static struct file_operations ezusb_fops = {
@@ -730,20 +962,12 @@ static int ezusb_probe(struct usb_device *usbdev)
 static void ezusb_disconnect(struct usb_device *usbdev)
 {
        struct ezusb *ez = (struct ezusb *)usbdev->private;
-       struct isodesc *isodesc;
 
        down(&ez->mutex);
-       while (!list_empty(&ez->iso)) {
-               isodesc = list_entry(ez->iso.next, struct isodesc, isolist);
-               list_del(ez->iso.next);
-               usb_delete_isochronous(ez->usbdev, isodesc->hcisodesc[0]);
-               usb_delete_isochronous(ez->usbdev, isodesc->hcisodesc[1]);
-               kfree(isodesc->hcbuf[0]);
-               kfree(isodesc->hcbuf[1]);
-               vfree(isodesc->buf);
-       }
+       destroy_all_async(ez);
        ez->usbdev = NULL;
        up(&ez->mutex);
+       wake_up(&ez->wait);
         usbdev->private = NULL;
        MOD_DEC_USE_COUNT;
 }
@@ -765,7 +989,10 @@ int ezusb_init(void)
        for (u = 0; u < NREZUSB; u++) {
                init_MUTEX(&ezusb[u].mutex);
                ezusb[u].usbdev = NULL;
-               INIT_LIST_HEAD(&ezusb[u].iso);
+               INIT_LIST_HEAD(&ezusb[u].async_pending);
+               INIT_LIST_HEAD(&ezusb[u].async_completed);
+               init_waitqueue_head(&ezusb[u].wait);
+               spin_lock_init(&ezusb[u].lock);
        }
        /* register misc device */
        if (misc_register(&ezusb_misc)) {
diff --git a/drivers/usb/hp_scanner.c b/drivers/usb/hp_scanner.c
new file mode 100644 (file)
index 0000000..12c7bf0
--- /dev/null
@@ -0,0 +1,344 @@
+/* -*- linux-c -*- */
+
+/* 
+ * Driver for USB HP Scanners
+ *
+ * David E. Nelson (dnelson@jump.net)
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Based upon mouse.c (Brad Keryan) and printer.c (Michael Gee).
+ *
+ * History
+ *  0.1  8/31/1999
+ *
+ *    Developed/tested using linux-2.3.15 with minor ohci.c changes to
+ *    support short packes during bulk xfer mode.  Some testing was
+ *    done with ohci-hcd but the performace was low.  Very limited
+ *    testing was performed with uhci but I was unable to get it to
+ *    work.  Initial relase to the linux-usb development effort.
+ *
+ * */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/random.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <asm/spinlock.h>
+
+#include "usb.h"
+
+/* stall/wait timeout for scanner */
+#define NAK_TIMEOUT (HZ)
+
+/* For some reason, an IBUF_SIZE of 8192 causes REALLY big problems
+ * with linux-2.3.15.  Anything more than 4k seems to not have an
+ * effect on increasing performance. Anything smaller than 4k hurts
+ * it.  */
+#define IBUF_SIZE 4096
+
+/* This is a scanner, so not much data is sent to it.  The largest
+ * stuff may be some kind of maps and stuff but that's kinda rare.  */
+#define OBUF_SIZE 128
+
+#define USB_SCANNER_MAJOR 16
+
+struct hpscan_usb_data {
+       struct usb_device       *hpscan_dev;            /* init: probe_scanner */
+       __u8                    isopen;                 /* nz if open */
+
+       __u8                    present;                /* Device is present on the bus */
+       char                    *obuf;                  /* transfer buffers */
+       char                    *ibuf;          
+       wait_queue_head_t       wait_q;                 /* for timeouts */
+};
+
+static struct hpscan_usb_data hpscan;
+
+static int
+open_scanner(struct inode * inode, struct file * file)
+{
+       struct hpscan_usb_data *hps = &hpscan;
+
+       if (hps->isopen) {
+               return -EBUSY;
+       }
+       hps->isopen = 1;
+
+       init_waitqueue_head(&hps->wait_q);
+
+       MOD_INC_USE_COUNT;
+
+       return 0;
+}
+
+static int
+close_scanner(struct inode * inode, struct file * file)
+{
+       struct hpscan_usb_data *hps = &hpscan;
+
+       hps->isopen = 0;
+
+       MOD_DEC_USE_COUNT;
+
+       return 0;
+}
+
+static ssize_t
+write_scanner(struct file * file, const char * buffer,
+              size_t count, loff_t *ppos)
+{
+       struct hpscan_usb_data *hps = &hpscan;
+
+       unsigned long copy_size;
+       unsigned long bytes_written = 0;
+       unsigned long partial;
+
+       int result = 0;
+       int maxretry;
+       
+       do {
+               unsigned long thistime;
+               char *obuf = hps->obuf;
+
+               thistime = copy_size = (count > OBUF_SIZE) ?  OBUF_SIZE : count;
+               if (copy_from_user(hps->obuf, buffer, copy_size))
+                       return -EFAULT;
+               maxretry = 5;
+               while (thistime) {
+                       if (!hps->hpscan_dev)
+                               return -ENODEV;
+                       if (signal_pending(current)) {
+                               return bytes_written ? bytes_written : -EINTR;
+                       }
+
+                       result = hps->hpscan_dev->bus->op->bulk_msg(hps->hpscan_dev,usb_sndbulkpipe(hps->hpscan_dev, 2), obuf, thistime, &partial);
+                       
+                       //printk(KERN_DEBUG "write stats: result:%d thistime:%lu partial:%lu\n", result, thistime, partial);
+
+                       if (result == USB_ST_TIMEOUT) { /* NAK - so hold for a while */
+                               if(!maxretry--) {
+                                       return -ETIME;
+                               }
+                               interruptible_sleep_on_timeout(&hps->wait_q, NAK_TIMEOUT);
+                               continue;
+                       } else if (!result & partial) {
+                               obuf += partial;
+                               thistime -= partial;
+                       } else
+                               break;
+               };
+               if (result) {
+                       printk("Write Whoops - %x\n", result);
+                       return -EIO;
+               }
+               bytes_written += copy_size;
+               count -= copy_size;
+               buffer += copy_size;
+       } while ( count > 0 );
+       
+       return bytes_written ? bytes_written : -EIO;
+}
+
+static ssize_t
+read_scanner(struct file * file, char * buffer,
+             size_t count, loff_t *ppos)
+{
+       struct hpscan_usb_data *hps = &hpscan;
+
+       ssize_t read_count;
+
+       unsigned long partial;
+
+       int this_read;
+       int result;
+
+/* Wait for the scanner to get it's act together.  This may involve
+ * resetting the head, warming up the lamp, etc.  maxretry is number
+ * of seconds.  */
+       int maxretry = 30; 
+
+       char *ibuf = hps->ibuf;
+
+       read_count = 0;
+
+       while (count) {
+               if (signal_pending(current)) {
+                       return read_count ? read_count : -EINTR;
+               }
+               if (!hps->hpscan_dev)
+                       return -ENODEV;
+               this_read = (count > IBUF_SIZE) ? IBUF_SIZE : count;
+               
+               result = hps->hpscan_dev->bus->op->bulk_msg(hps->hpscan_dev, usb_rcvbulkpipe(hps->hpscan_dev, 1), ibuf, this_read, &partial);
+
+               printk(KERN_DEBUG "read stats: result:%d this_read:%u partial:%lu\n", result, this_read, partial);
+               
+               if (partial) {
+                       count = this_read = partial;
+               } else if (result == USB_ST_TIMEOUT || result == 15) {
+                       if(!maxretry--) {
+                               printk(KERN_DEBUG "read_scanner: maxretry timeout\n");
+                               return -ETIME;
+                       }
+                       interruptible_sleep_on_timeout(&hps->wait_q, NAK_TIMEOUT);
+                       continue;
+               } else if (result != USB_ST_DATAUNDERRUN) {
+                       printk("Read Whoops - result:%u partial:%lu this_read:%u\n", result, partial, this_read);
+                       return -EIO;
+               } else {
+                       return (0);
+               }
+               
+               if (this_read) {
+                       if (copy_to_user(buffer, ibuf, this_read))
+                               return -EFAULT;
+                       count -= this_read;
+                       read_count += this_read;
+                       buffer += this_read;
+               }
+       }
+       return read_count;
+}
+
+static int
+probe_scanner(struct usb_device *dev)
+{
+       struct hpscan_usb_data *hps = &hpscan;
+
+       /*
+        * Don't bother using an HP 4200C since it does NOT understand
+        * SCL and HP isn't going to be releasing the specs any time
+        * soon.  */
+       if (dev->descriptor.idVendor != 0x3f0 ) {
+               printk(KERN_INFO "Scanner is not an HP Scanner.\n");
+               return -1;
+       }
+
+       if (dev->descriptor.idProduct != 0x101 && /* HP 4100C */
+           dev->descriptor.idProduct != 0x202 && /* HP 5100C */
+            dev->descriptor.idProduct != 0x601) { /* HP 6300C */
+               printk(KERN_INFO "Scanner model not supported/tested.\n");
+               return -1;
+       }
+       
+       printk(KERN_DEBUG "USB Scanner found at address %d\n", dev->devnum);
+       
+       if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) {
+               printk(KERN_DEBUG "Failed to set configuration\n");
+               return -1;
+       }
+
+       hps->present = 1;
+       hps->hpscan_dev = dev;
+
+       if (!(hps->obuf = (char *)kmalloc(OBUF_SIZE, GFP_KERNEL))) {
+               return -ENOMEM;
+       }
+
+       if (!(hps->ibuf = (char *)kmalloc(IBUF_SIZE, GFP_KERNEL))) {
+               return -ENOMEM;
+       }
+  
+       return 0;
+}
+
+static void
+disconnect_scanner(struct usb_device *dev)
+{
+       struct hpscan_usb_data *hps = &hpscan;
+
+       if (hps->isopen) {
+               /* better let it finish - the release will do whats needed */
+               hps->hpscan_dev = NULL;
+               return;
+       }
+       kfree(hps->ibuf);
+       kfree(hps->obuf);
+
+       dev->private = NULL;            /* just in case */
+       hps->present = 0;
+}
+
+static struct
+usb_driver scanner_driver = {
+       "usbscanner",
+       probe_scanner,
+       disconnect_scanner,
+       { NULL, NULL }
+};
+
+static struct
+file_operations usb_scanner_fops = {
+       NULL,           /* seek */
+       read_scanner,
+       write_scanner,
+       NULL,           /* readdir */
+       NULL,           /* poll */
+       NULL,           /* ioctl */
+       NULL,           /* mmap */
+       open_scanner,
+       NULL,           /* flush */
+       close_scanner,
+       NULL,         
+       NULL,         /* fasync */
+};
+
+int
+usb_hp_scanner_init(void)
+{
+       int result;
+       
+       if ((result = register_chrdev(USB_SCANNER_MAJOR, "usbscanner", &usb_scanner_fops)) < 0) {
+               printk(KERN_WARNING "hp_scanner: Cannot register device\n");
+               return result;
+       }
+       usb_register(&scanner_driver);
+       printk(KERN_DEBUG "USB Scanner support registered.\n");
+       return 0;
+}
+
+
+void
+usb_hp_scanner_cleanup(void)
+{
+       struct hpscan_usb_data *hps = &hpscan;
+
+       hps->present = 0;
+       usb_deregister(&scanner_driver);
+       unregister_chrdev(USB_SCANNER_MAJOR, "usbscanner");
+}
+
+#ifdef MODULE
+
+int
+init_module(void)
+{
+       return usb_hp_scanner_init();
+}
+
+void
+cleanup_module(void)
+{
+       usb_hp_scanner_cleanup();
+}
+#endif
+
index 28636769904a6d6db58445c2bd43945a3510e5c6..cc49fbbd5d413e2c735f14625de150ca451c4748 100644 (file)
@@ -5,5 +5,6 @@ int usb_acm_init(void);
 int usb_printer_init(void);
 void usb_hub_cleanup(void);
 void usb_mouse_cleanup(void);
+int usb_scsi_init(void);
 int proc_usb_init (void);
 void proc_usb_cleanup (void);
index f46c3ab64c5de793c5795b080b58367f855e51fd..4c7b0c6d818c319e3b1b6322f621e75e64eb2298 100644 (file)
@@ -4,6 +4,12 @@
  *
  * Brad Keryan 4/3/1999
  *
+ * version 0.30? Paul Ashton 1999/08/19 - Fixed behaviour on mouse
+ * disconnect and suspend/resume. Added module parameter "force=1"
+ * to allow opening of the mouse driver before mouse has been plugged
+ * in (enables consistent XF86Config settings). Fixed module use count.
+ * Documented missing blocking/non-blocking read handling (not fixed).
+ * 
  * version 0.20: Linus rewrote read_mouse() to do PS/2 and do it
  * correctly. Events are added together, not queued, to keep the rodent sober.
  *
@@ -49,6 +55,7 @@ struct mouse_state {
        int present; /* this mouse is plugged in */
        int active; /* someone is has this mouse's device open */
        int ready; /* the mouse has changed state since the last read */
+       int suspended; /* mouse disconnected */
        wait_queue_head_t wait; /* for polling */
        struct fasync_struct *fasync;
        /* later, add a list here to support multiple mice */
@@ -65,12 +72,38 @@ static struct mouse_state static_mouse_state;
 
 spinlock_t usb_mouse_lock = SPIN_LOCK_UNLOCKED;
 
+static int force=0; /* allow the USB mouse to be opened even if not there (yet) */
+MODULE_PARM(force,"i");
+
 static int mouse_irq(int state, void *__buffer, int len, void *dev_id)
 {
        signed char *data = __buffer;
        /* finding the mouse is easy when there's only one */
        struct mouse_state *mouse = &static_mouse_state; 
 
+       if (state)
+               printk(KERN_DEBUG "%s(%d):state %d, bp %p, len %d, dp %p\n",
+                       __FILE__, __LINE__, state, __buffer, len, dev_id);
+
+       /*
+        * USB_ST_NOERROR is the normal case.
+        * USB_ST_REMOVED occurs if mouse disconnected or suspend/resume
+        * USB_ST_INTERNALERROR occurs if system suspended then mouse removed
+        *    followed by resume. On UHCI could then occur every second
+        * In both cases, suspend the mouse
+        * On other states, ignore
+        */
+       switch (state) {
+       case USB_ST_REMOVED:
+       case USB_ST_INTERNALERROR: 
+               printk(KERN_DEBUG "%s(%d): Suspending\n",
+                       __FILE__, __LINE__);
+               mouse->suspended = 1;
+               return 0; /* disable */
+       case USB_ST_NOERROR: break;
+       default: return 1; /* ignore */
+       }       
+
        /* if a mouse moves with no one listening, do we care? no */
        if(!mouse->active)
                return 1;
@@ -110,9 +143,11 @@ static int release_mouse(struct inode * inode, struct file * file)
 
        fasync_mouse(-1, file, 0);
 
+       printk(KERN_DEBUG "%s(%d): MOD_DEC\n", __FILE__, __LINE__);
        MOD_DEC_USE_COUNT;
 
        if (--mouse->active == 0) {
+               mouse->suspended = 0;
                /* stop polling the mouse while its not in use */
                usb_release_irq(mouse->dev, mouse->irq_handle);
                /* never keep a reference to a released IRQ! */
@@ -126,15 +161,38 @@ static int open_mouse(struct inode * inode, struct file * file)
 {
        struct mouse_state *mouse = &static_mouse_state;
 
+       printk(KERN_DEBUG "%s(%d): open_mouse\n", __FILE__, __LINE__);
+       /*
+        * First open may fail since mouse_probe() may get called after this
+        * if module load is in response to the open
+        * mouse_probe() sets mouse->present. This open can be delayed by
+        * specifying force=1 in module load
+        * This helps if you want to insert the USB mouse after starting X
+        */
        if (!mouse->present)
-               return -EINVAL;
+       {
+               if (force) /* always load the driver even if no mouse (yet) */
+               {
+                       printk(KERN_DEBUG "%s(%d): forced open\n",
+                               __FILE__, __LINE__);
+                       mouse->suspended = 1;
+               }
+               else
+                       return -EINVAL;
+       }
+
+       /* prevent the driver from being unloaded while its in use */
+       printk(KERN_DEBUG "%s(%d): MOD_INC\n", __FILE__, __LINE__);
+       /* Increment use count even if already active */
+       MOD_INC_USE_COUNT;
+
        if (mouse->active++)
                return 0;
        /* flush state */
        mouse->buttons = mouse->dx = mouse->dy = mouse->dz = 0;
 
-       /* prevent the driver from being unloaded while its in use */
-       MOD_INC_USE_COUNT;
+       if (!mouse->present) /* only get here if force == 1 */
+               return 0;
 
        /* start the usb controller's polling of the mouse */
        mouse->irq_handle = usb_request_irq(mouse->dev, usb_rcvctrlpipe(mouse->dev, mouse->bEndpointAddress), mouse_irq, mouse->bInterval, NULL);
@@ -160,6 +218,10 @@ static ssize_t read_mouse(struct file * file, char * buffer, size_t count, loff_
        static int state = 0;
        struct mouse_state *mouse = &static_mouse_state;
 
+       /*
+        * FIXME - Other mouse drivers handle blocking and nonblocking reads
+        * differently here...
+        */
        if (count) {
                mouse->ready = 0;
                switch (state) {
@@ -304,6 +366,19 @@ static int mouse_probe(struct usb_device *dev)
        mouse->bInterval = endpoint->bInterval;
 
        mouse->present = 1;
+
+       /* This appears to let USB mouse survive disconnection and */
+       /* APM suspend/resume */
+       if (mouse->suspended)
+       {
+               printk(KERN_DEBUG "%s(%d): mouse resume\n", __FILE__, __LINE__);
+               /* restart the usb controller's polling of the mouse */
+               mouse->irq_handle = usb_request_irq(mouse->dev,
+                       usb_rcvctrlpipe(mouse->dev, mouse->bEndpointAddress),
+                       mouse_irq, mouse->bInterval, NULL);
+               mouse->suspended = 0;
+       }
+
        return 0;
 }
 
@@ -315,7 +390,6 @@ static void mouse_disconnect(struct usb_device *dev)
        if (mouse->present) {
                usb_release_irq(mouse->dev, mouse->irq_handle);
                /* never keep a reference to a released IRQ! */
-               mouse->irq_handle = NULL;
        }
 
        mouse->irq_handle = NULL;
@@ -336,7 +410,7 @@ int usb_mouse_init(void)
 {
        struct mouse_state *mouse = &static_mouse_state;
 
-       mouse->present = mouse->active = 0;
+       mouse->present = mouse->active = mouse->suspended = 0;
        mouse->irq_handle = NULL;
        init_waitqueue_head(&mouse->wait);
        mouse->fasync = NULL;
index cc3fe6a2adcd7ecb1d1f39b418d7a49b2cd0dbc0..b73af5553ed6d30029be7be70fc4a6cebca62146 100644 (file)
@@ -1455,7 +1455,7 @@ static void * ohci_request_bulk(struct usb_device *usb_dev, unsigned int pipe, u
 
        return ohci_generic_trans(usb_dev, pipe,
                        TOGGLE_AUTO,
-                       1 /* round */, 1 /* autofree */,
+                       0 /* round */, 1 /* autofree */,
                        dev_id, handler, data, len,
                        HCD_ED_BULK,
                        NULL /* no setup_td */, NULL /* no status_td */ );
@@ -1504,7 +1504,7 @@ static int ohci_bulk_msg_td_handler(int stats, void *buffer, int len, void *dev_
 #endif
 
        /* only count TDs that were completed successfully */
-       if (stats == USB_ST_NOERROR)
+       if (stats == USB_ST_NOERROR || stats == USB_ST_DATAUNDERRUN) /*DEN*/
                req->_bytes_done += len;
 
 #ifdef OHCI_DEBUG
index 1204951b20be10a3945d8df83e7a4dd4150a42f9..d6e21e009792d605ca13a59e11904946516e6879 100644 (file)
 /* 4/4/1999 added data toggle for interrupt pipes -keryan */
 /* 5/16/1999 added global toggles for bulk and control */
 /* 6/25/1999 added fix for data toggles on bidirectional bulk endpoints */ 
+/*
+ * 1999-09-02: Thomas Sailer <sailer@ife.ee.ethz.ch>
+ *             Added explicit frame list manipulation routines
+ *             for inserting/removing iso td's to/from the frame list.
+ *             START_ABSOLUTE fixes
+ */
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -462,6 +468,84 @@ static void uhci_remove_irq_list(struct uhci_td *td)
        spin_unlock_irqrestore(&irqlist_lock, flags);
 }
 
+/*
+ * frame list manipulation. Used for Isochronous transfers.
+ * the list of (iso) TD's enqueued in a frame list entry
+ * is basically a doubly linked list with link being
+ * the forward pointer and backptr the backward ptr.
+ * the frame list entry itself doesn't have a back ptr
+ * (therefore the list is not circular), and the forward pointer
+ * stops at link entries having the UHCI_PTR_TERM or the UHCI_PTR_QH
+ * bit set. Maybe it could be extended to handle the QH's also,
+ * but it doesn't seem necessary right now.
+ * The layout looks as follows:
+ * frame list pointer -> iso td's (if any) -> 
+ * periodic interrupt td (if framelist 0) -> irq qh -> control qh -> bulk qh
+ */
+
+static spinlock_t framelist_lock = SPIN_LOCK_UNLOCKED;
+
+static void uhci_add_frame_list(struct uhci *uhci, struct uhci_td *td, unsigned framenum)
+{
+       unsigned long flags;
+       struct uhci_td *nexttd;
+
+       framenum %= UHCI_NUMFRAMES;
+       spin_lock_irqsave(&framelist_lock, flags);
+       td->backptr = &uhci->fl->frame[framenum];
+       td->link = uhci->fl->frame[framenum];
+       if (!(td->link & (UHCI_PTR_TERM | UHCI_PTR_QH))) {
+               nexttd = (struct uhci_td *)bus_to_virt(td->link & ~15);
+               nexttd->backptr = &td->link;
+       }
+       wmb();
+       uhci->fl->frame[framenum] = virt_to_bus(td);
+       spin_unlock_irqrestore(&framelist_lock, flags);
+}
+
+static void uhci_remove_frame_list(struct uhci *uhci, struct uhci_td *td)
+{
+       unsigned long flags;
+       struct uhci_td *nexttd;
+
+       if (!td->backptr)
+               return;
+       spin_lock_irqsave(&framelist_lock, flags);
+       *(td->backptr) = td->link;
+       if (!(td->link & (UHCI_PTR_TERM | UHCI_PTR_QH))) {
+               nexttd = (struct uhci_td *)bus_to_virt(td->link & ~15);
+               nexttd->backptr = td->backptr;
+       }
+       spin_unlock_irqrestore(&framelist_lock, flags);
+       td->backptr = NULL;
+       /*
+        * attention: td->link might still be in use by the
+        * hardware if the td is still active and the hardware
+        * was processing it. So td->link should be preserved
+        * until the frame number changes. Don't know what to do...
+        * udelay(1000) doesn't sound nice, and schedule()
+        * can't be used as this is called from within interrupt context.
+        */
+       /* for now warn if there's a possible problem */
+       if (td->status & TD_CTRL_ACTIVE) {
+               unsigned frn = inw(uhci->io_addr + USBFRNUM);
+               __u32 link = uhci->fl->frame[frn % UHCI_NUMFRAMES];
+               if (!(link & (UHCI_PTR_TERM | UHCI_PTR_QH))) {
+                       struct uhci_td *tdl = (struct uhci_td *)bus_to_virt(link & ~15);
+                       for (;;) {
+                               if (tdl == td) {
+                                       printk(KERN_WARNING "uhci_remove_frame_list: td possibly still in use!!\n");
+                                       break;
+                               }
+                               if (tdl->link & (UHCI_PTR_TERM | UHCI_PTR_QH))
+                                       break;
+                               tdl = (struct uhci_td *)bus_to_virt(tdl->link & ~15);
+                       }
+               }       
+       }
+}
+
+
 /*
  * This function removes and disallocates all structures set up for a transfer.
  * It takes the qh out of the skeleton, removes the tq and the td's.
@@ -619,6 +703,7 @@ static int uhci_init_isoc (struct usb_device *usb_dev,
                                struct usb_isoc_desc **isocdesc)
 {
        struct usb_isoc_desc *id;
+       int i;
 
 #ifdef BANDWIDTH_ALLOCATION
        /* TBD: add bandwidth allocation/checking/management HERE. */
@@ -628,7 +713,7 @@ static int uhci_init_isoc (struct usb_device *usb_dev,
        *isocdesc = NULL;
 
        /* Check some parameters. */
-       if ((frame_count < 0) || (frame_count > UHCI_NUMFRAMES)) {
+       if ((frame_count <= 0) || (frame_count > UHCI_NUMFRAMES)) {
 #ifdef CONFIG_USB_DEBUG_ISOC
                printk (KERN_DEBUG "uhci_init_isoc: invalid frame_count (%d)\n",
                        frame_count);
@@ -648,16 +733,20 @@ static int uhci_init_isoc (struct usb_device *usb_dev,
        if (!id)
                return -ENOMEM;
 
+       memset (id, 0, sizeof (*id) +
+               (sizeof (struct isoc_frame_desc) * frame_count));
+
        id->td = kmalloc (sizeof (struct uhci_td) * frame_count, GFP_KERNEL);
        if (!id->td) {
                kfree (id);
                return -ENOMEM;
        }
 
-       memset (id, 0, sizeof (*id) +
-               (sizeof (struct isoc_frame_desc) * frame_count));
        memset (id->td, 0, sizeof (struct uhci_td) * frame_count);
 
+       for (i = 0; i < frame_count; i++)
+               INIT_LIST_HEAD(&((struct uhci_td *)(id->td))[i].irq_list);
+
        id->frame_count = frame_count;
        id->frame_size  = usb_maxpacket (usb_dev, pipe, usb_pipeout(pipe));
                /* TBD: or make this a parameter to allow for frame_size
@@ -755,7 +844,7 @@ static int uhci_run_isoc (struct usb_isoc_desc *isocdesc,
        cur_frame = uhci_get_current_frame_number (isocdesc->usb_dev);
 
        /* if not START_ASAP (i.e., RELATIVE or ABSOLUTE): */
-       if (!pr_isocdesc)
+       if (!pr_isocdesc) {
                if (isocdesc->start_type == START_RELATIVE) {
                        if ((isocdesc->start_frame < 0) || (isocdesc->start_frame > CAN_SCHEDULE_FRAMES)) {
 #ifdef CONFIG_USB_DEBUG_ISOC
@@ -766,9 +855,10 @@ static int uhci_run_isoc (struct usb_isoc_desc *isocdesc,
                        }
                } /* end START_RELATIVE */
                else
-               if (isocdesc->start_type == START_ABSOLUTE) {
-                       if (isocdesc->start_frame > cur_frame) {
-                               if ((isocdesc->start_frame - cur_frame) > CAN_SCHEDULE_FRAMES) {
+               if (isocdesc->start_type == START_ABSOLUTE) { /* within the scope of cur_frame */
+                       ix = USB_WRAP_FRAMENR(isocdesc->start_frame - cur_frame);
+                       if (ix < START_FRAME_FUDGE || /* too small */
+                           ix > CAN_SCHEDULE_FRAMES) { /* too large */
 #ifdef CONFIG_USB_DEBUG_ISOC
                                        printk (KERN_DEBUG "uhci_init_isoc: bad start_frame value (%d)\n",
                                                isocdesc->start_frame);
@@ -787,6 +877,7 @@ static int uhci_run_isoc (struct usb_isoc_desc *isocdesc,
                                }
                        }
                } /* end START_ABSOLUTE */
+       }
 
        /*
         * Set the start/end frame numbers.
@@ -800,16 +891,14 @@ static int uhci_run_isoc (struct usb_isoc_desc *isocdesc,
        } else if (isocdesc->start_type == START_ASAP) {
                isocdesc->start_frame = cur_frame + START_FRAME_FUDGE;
        }
-       /* else for start_type == START_ABSOLUTE, use start_frame as is. */
 
        /* and see if start_frame needs any correction */
-       if (isocdesc->start_frame >= UHCI_NUMFRAMES)
-               isocdesc->start_frame -= UHCI_NUMFRAMES;
+       /* only wrap to USB frame numbers, the frame_list insertion routine
+          takes care of the wrapping to the frame_list size */
+       isocdesc->start_frame = USB_WRAP_FRAMENR(isocdesc->start_frame);
 
        /* and fix the end_frame value */
-       isocdesc->end_frame = isocdesc->start_frame + isocdesc->frame_count - 1;
-       if (isocdesc->end_frame >= UHCI_NUMFRAMES)
-               isocdesc->end_frame -= UHCI_NUMFRAMES;
+       isocdesc->end_frame = USB_WRAP_FRAMENR(isocdesc->start_frame + isocdesc->frame_count - 1);
 
        isocdesc->prev_completed_frame = -1;
        isocdesc->cur_completed_frame  = -1;
@@ -857,6 +946,7 @@ static int uhci_run_isoc (struct usb_isoc_desc *isocdesc,
                        td->status |= TD_CTRL_IOC;
                        td->completed = isocdesc->callback_fn;
                        cb_frames = 0;
+                       uhci_add_irq_list (dev->uhci, td, isocdesc->callback_fn, isocdesc->context);
                }
 
                bufptr += fd->frame_length;  /* or isocdesc->frame_size; */
@@ -864,21 +954,20 @@ static int uhci_run_isoc (struct usb_isoc_desc *isocdesc,
                /*
                 * Insert the TD in the frame list.
                 */
-               td->backptr = &uhci->fl->frame [cur_frame];
-               td->link    = uhci->fl->frame [cur_frame];
-               uhci->fl->frame [cur_frame] = virt_to_bus (td);
+               uhci_add_frame_list(uhci, td, cur_frame);
 
-               if (++cur_frame >= UHCI_NUMFRAMES)
-                       cur_frame = 0;
+               cur_frame = USB_WRAP_FRAMENR(cur_frame+1);
        } /* end for ix */
 
        /*
         * Add IOC on the last TD.
         */
        td--;
-       td->status |= TD_CTRL_IOC;
-       uhci_add_irq_list (dev->uhci, td, isocdesc->callback_fn, isocdesc->context); /* TBD: D.K. ??? */
-
+       if (!(td->status & TD_CTRL_IOC)) {
+               td->status |= TD_CTRL_IOC;
+               td->completed = isocdesc->callback_fn;
+               uhci_add_irq_list(dev->uhci, td, isocdesc->callback_fn, isocdesc->context); /* TBD: D.K. ??? */
+       }
        return 0;
 } /* end uhci_run_isoc */
 
@@ -897,9 +986,9 @@ static int uhci_kill_isoc (struct usb_isoc_desc *isocdesc)
        struct uhci_device *dev = usb_to_uhci (isocdesc->usb_dev);
        struct uhci     *uhci = dev->uhci;
        struct uhci_td  *td;
-       int             ix, cur_frame;
+       int             ix;
 
-       if ((isocdesc->start_frame < 0) || (isocdesc->start_frame >= UHCI_NUMFRAMES)) {
+       if (USB_WRAP_FRAMENR(isocdesc->start_frame) != isocdesc->start_frame) {
 #ifdef CONFIG_USB_DEBUG_ISOC
                printk (KERN_DEBUG "uhci_kill_isoc: invalid start_frame (%d)\n",
                        isocdesc->start_frame);
@@ -907,13 +996,9 @@ static int uhci_kill_isoc (struct usb_isoc_desc *isocdesc)
                return -EINVAL;
        }
 
-       for (ix = 0, td = isocdesc->td, cur_frame = isocdesc->start_frame;
-            ix < isocdesc->frame_count; ix++, td++) {
+       for (ix = 0, td = isocdesc->td; ix < isocdesc->frame_count; ix++, td++) {
+               uhci_remove_frame_list(uhci, td);
                td->status &= ~(TD_CTRL_ACTIVE | TD_CTRL_IOC);
-               uhci->fl->frame [cur_frame] = td->link;
-
-               if (++cur_frame >= UHCI_NUMFRAMES)
-                       cur_frame = 0;
        } /* end for ix */
 
        isocdesc->start_frame = -1;
@@ -922,18 +1007,21 @@ static int uhci_kill_isoc (struct usb_isoc_desc *isocdesc)
 
 static void uhci_free_isoc (struct usb_isoc_desc *isocdesc)
 {
+       int i;
+
        /* If still Active, kill it. */
        if (isocdesc->start_frame >= 0)
-               uhci_kill_isoc (isocdesc);
+               uhci_kill_isoc(isocdesc);
 
-       /* Remove it from the IRQ list. */
-       uhci_remove_irq_list ((struct uhci_td *)&(isocdesc->td [isocdesc->frame_count - 1]));
+       /* Remove all td's from the IRQ list. */
+       for(i = 0; i < isocdesc->frame_count; i++)
+               uhci_remove_irq_list(((struct uhci_td *)(isocdesc->td))+i);
 
        /* Free the associate memory. */
        if (isocdesc->td)
-               kfree (isocdesc->td);
+               kfree(isocdesc->td);
 
-       kfree (isocdesc);
+       kfree(isocdesc);
 } /* end uhci_free_isoc */
 
 /*
@@ -1512,7 +1600,7 @@ static int fixup_isoc_desc (struct uhci_td *td)
                        td, isocdesc, first_comp, cur_comp, num_comp);
 #endif
 
-       for (ix = 0, fx = first_comp, prtd = &isocdesc->td [first_comp], frm = &isocdesc->frames [first_comp];
+       for (ix = 0, fx = first_comp, prtd = ((struct uhci_td *)(isocdesc->td))+first_comp, frm = &isocdesc->frames [first_comp];
            ix < num_comp; ix++) {
                frm->frame_length = uhci_actual_length (prtd->status);
                isocdesc->total_length += frm->frame_length;
@@ -1666,6 +1754,7 @@ static void uhci_init_ticktd(struct uhci *uhci)
 
        /* Don't clobber the frame */
        td->link = uhci->fl->frame[0];
+       td->backptr = &uhci->fl->frame[0];
        td->status = TD_CTRL_IOC;
        td->info = (15 << 21) | (0x7f << 8) | USB_PID_IN;       /* (ignored) input packet, 16 bytes, device 127 */
        td->buffer = 0;
index 2103789a88684092dd02cb15ff1941579ae5f6a4..6692dd796a0a5132a9ed6165fb794ed7ba50c806 100644 (file)
@@ -44,6 +44,9 @@ int usb_init(void)
 #      ifdef CONFIG_USB_MOUSE
                usb_mouse_init();
 #      endif
+#       ifdef CONFIG_USB_HP_SCANNER
+                usb_hp_scanner_init();
+#       endif
 #      ifdef CONFIG_USB_KBD
                usb_kbd_init();
 #      endif
@@ -86,6 +89,9 @@ void cleanup_drivers(void)
 #      ifdef CONFIG_USB_MOUSE
                usb_mouse_cleanup();
 #      endif
+#       ifdef CONFIG_USB_HP_SCANNER
+                usb_hp_scanner_cleanup();
+#       endif
 #endif
 }
 
index 18fcfd5ad9c597e786471a90d0b95e67c780ef71..4c76a3c896ccb110665b10dea399f615aade7b16 100644 (file)
@@ -349,6 +349,8 @@ typedef int (*usb_device_irq)(int, void *, int, void *);
  */
 #define START_FRAME_FUDGE      3
 
+#define USB_WRAP_FRAMENR(x) ((x) & 2047)
+
 /* for start_type: */
 enum {
        START_ASAP = 0,
@@ -528,13 +530,6 @@ extern void usb_disconnect(struct usb_device **);
 
 extern void usb_destroy_configuration(struct usb_device *dev);
 
-extern void *usb_allocate_isochronous (struct usb_device *usb_dev, unsigned int pipe, void *data, int len,
-                                       int maxsze, usb_device_irq completed, void *dev_id);
-extern void usb_delete_isochronous (struct usb_device *dev, void *_isodesc);
-extern int usb_schedule_isochronous (struct usb_device *usb_dev, void *_isodesc, void *_pisodesc);
-extern int usb_unschedule_isochronous (struct usb_device *usb_dev, void *_isodesc);
-extern int usb_compress_isochronous (struct usb_device *usb_dev, void *_isodesc);
-
 int usb_get_current_frame_number (struct usb_device *usb_dev);
 
 int usb_init_isoc (struct usb_device *usb_dev,
index 7752d5bd41f3fe0acd3b8353b04903ddbb8e3e0f..690b8ab049b8c728949432fe1c5490d0643ff758 100644 (file)
@@ -92,6 +92,7 @@ struct us_data {
        int                     ip_wanted;              /* needed */
        int                     pid;                    /* control thread */
        struct semaphore        *notify;                /* wait for thread to begin */
+       void                    *irq_handle;            /* for USB interrupt requests */
 };
 
 /*
@@ -374,6 +375,7 @@ static int pop_CB_status(Scsi_Cmnd *srb)
     __u8 status[2];
     devrequest dr;
     int retry = 5;
+    void *irq_handle;
 
     US_DEBUGP("pop_CB_status, proto=%x\n", us->protocol);
     switch (us->protocol) {
@@ -409,13 +411,15 @@ static int pop_CB_status(Scsi_Cmnd *srb)
 
        /* add interrupt transfer, marked for removal */
        us->ip_wanted = 1;
-       result = us->pusb_dev->bus->op->request_irq(us->pusb_dev, 
+       irq_handle = us->pusb_dev->bus->op->request_irq(us->pusb_dev, 
                                                    usb_rcvctrlpipe(us->pusb_dev, us->ep_int),
                                                     pop_CBI_irq, 0, (void *)us);
-       if (result) {
-           US_DEBUGP("No interrupt for CBI %x\n", result);
+       if (!irq_handle) {
+           US_DEBUGP("No interrupt for CBI\n");
            return DID_ABORT << 16;
        }
+       us->irq_handle = irq_handle;
+
        sleep_on(&us->ip_waitq);
        if (us->ip_wanted) {
            US_DEBUGP("Did not get interrupt on CBI\n");
@@ -647,13 +651,17 @@ static int us_release(struct Scsi_Host *psh)
     struct us_data *us = (struct us_data *)psh->hostdata[0];
     struct us_data *prev = (struct us_data *)&us_list;
 
+    if (us->irq_handle) {
+       usb_release_irq(us->pusb_dev, us->irq_handle);
+       us->irq_handle = NULL;
+    }
     if (us->filter)
        us->filter->release(us->fdata);
     if (us->pusb_dev)
        usb_deregister(&scsi_driver);
 
     /* FIXME - leaves hanging host template copy */
-    /* (bacause scsi layer uses it after removal !!!) */
+    /* (because scsi layer uses it after removal !!!) */
     while(prev->next != us)
        prev = prev->next;
     prev->next = us->next;
@@ -1280,6 +1288,7 @@ static int scsi_probe(struct usb_device *dev)
            dev->descriptor.idProduct == 0x0001) {
            devrequest dr;
            __u8 qstat[2];
+           void *irq_handle;
 
            /* shuttle E-USB */
            dr.requesttype = 0xC0;
@@ -1290,9 +1299,12 @@ static int scsi_probe(struct usb_device *dev)
            ss->pusb_dev->bus->op->control_msg(ss->pusb_dev, usb_rcvctrlpipe(dev,0), &dr, qstat, 2);
            US_DEBUGP("C0 status %x %x\n", qstat[0], qstat[1]);
            init_waitqueue_head(&ss->ip_waitq);
-           ss->pusb_dev->bus->op->request_irq(ss->pusb_dev, 
+           irq_handle = ss->pusb_dev->bus->op->request_irq(ss->pusb_dev, 
                                                usb_rcvctrlpipe(ss->pusb_dev, ss->ep_int),
                                                pop_CBI_irq, 0, (void *)ss);
+           if (!irq_handle)
+               return -1;
+           ss->irq_handle = irq_handle;
            interruptible_sleep_on_timeout(&ss->ip_waitq, HZ*5);
 
        } else if (ss->protocol == US_PR_CBI)
index d1813c19146c7d19d6f6b1105e891ca3b2c32036..ea6b7e94f317b987bca50cb14f0c0e06a9408bab 100644 (file)
@@ -71,11 +71,10 @@ if [ "$CONFIG_INET" = "y" ]; then
   if [ "$CONFIG_NFS_FS" = "y" -a "$CONFIG_IP_PNP" = "y" ]; then
     bool '   Root file system on NFS' CONFIG_ROOT_NFS
   fi
-  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-    tristate 'NFS server support' CONFIG_NFSD
-    if [ "$CONFIG_NFSD" != "n" ]; then
-      bool '   Emulate SUN NFS server' CONFIG_NFSD_SUN
-    fi
+  # considering that RedHat-6.0 ships with this on, I guess it's not really experimental
+  tristate 'NFS server support' CONFIG_NFSD
+  if [ "$CONFIG_NFSD" != "n" ]; then
+    bool '   Emulate SUN NFS server' CONFIG_NFSD_SUN
   fi
   if [ "$CONFIG_NFS_FS" = "y" -o "$CONFIG_NFSD" = "y" ]; then
     define_bool CONFIG_SUNRPC y
index 3a60710aa8237ec970697afff925d036ad998f6b..c4fefe5cc1bc3ead231f85cf89ed6b60d4061b81 100644 (file)
@@ -898,19 +898,21 @@ void __brelse(struct buffer_head * buf)
  */
 void __bforget(struct buffer_head * buf)
 {
+       /* grab the lru lock here to block bdflush. */
        spin_lock(&lru_list_lock);
        write_lock(&hash_table_lock);
-       if (atomic_read(&buf->b_count) != 1 || buffer_locked(buf)) {
-               touch_buffer(buf);
-               atomic_dec(&buf->b_count);
-       } else {
-               atomic_set(&buf->b_count, 0);
-               buf->b_state = 0;
-               if (buf->b_pprev)
-                       __hash_unlink(buf);
-               __remove_from_lru_list(buf, buf->b_list);
-               put_last_free(buf);
-       }
+       if (!atomic_dec_and_test(&buf->b_count) || buffer_locked(buf))
+               goto in_use;
+       if (buf->b_pprev)
+               __hash_unlink(buf);
+       write_unlock(&hash_table_lock);
+       __remove_from_lru_list(buf, buf->b_list);
+       spin_unlock(&lru_list_lock);
+       buf->b_state = 0;
+       put_last_free(buf);
+       return;
+
+ in_use:
        write_unlock(&hash_table_lock);
        spin_unlock(&lru_list_lock);
 }
@@ -1231,16 +1233,12 @@ int block_flushpage(struct inode *inode, struct page *page, unsigned long offset
                 */
                if (offset <= curr_off) {
                        if (buffer_mapped(bh)) {
-                               atomic_inc(&bh->b_count);
-                               wait_on_buffer(bh);
-                               if (bh->b_dev == B_FREE)
-                                       BUG();
                                mark_buffer_clean(bh);
+                               wait_on_buffer(bh);
                                clear_bit(BH_Uptodate, &bh->b_state);
                                clear_bit(BH_Mapped, &bh->b_state);
                                clear_bit(BH_Req, &bh->b_state);
                                bh->b_blocknr = 0;
-                               atomic_dec(&bh->b_count);
                        }
                }
                curr_off = next_off;
@@ -1258,8 +1256,7 @@ int block_flushpage(struct inode *inode, struct page *page, unsigned long offset
         * instead.
         */
        if (!offset) {
-               if (!try_to_free_buffers(page))
-               {
+               if (!try_to_free_buffers(page)) {
                        atomic_add(PAGE_CACHE_SIZE, &buffermem);
                        return 0;
                }
index a4e99543278753eb1c8c56aac2e5a4f5e4070bc6..52e97c58558f16b9118941bfb34234a27e1b62d8 100644 (file)
@@ -856,10 +856,11 @@ int ext2_notify_change(struct dentry *dentry, struct iattr *iattr)
        unsigned int    flags;
        
        retval = -EPERM;
-       if ((iattr->ia_attr_flags &
-            (ATTR_FLAG_APPEND | ATTR_FLAG_IMMUTABLE)) ^
-           (inode->u.ext2_i.i_flags &
-            (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL))) {
+       if (iattr->ia_valid & ATTR_ATTR_FLAG &&
+           ((!(iattr->ia_attr_flags & ATTR_FLAG_APPEND) !=
+             !(inode->u.ext2_i.i_flags & EXT2_APPEND_FL)) ||
+            (!(iattr->ia_attr_flags & ATTR_FLAG_IMMUTABLE) !=
+             !(inode->u.ext2_i.i_flags & EXT2_IMMUTABLE_FL)))) {
                if (!capable(CAP_LINUX_IMMUTABLE))
                        goto out;
        } else if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
index 873a8cf4be608517deeafcda05ae14367e29411d..81ac20840d2d0db9a751db0685499d16b273205f 100644 (file)
@@ -176,7 +176,7 @@ static int do_ncp_rpc_call(struct ncp_server *server, int size,
                   instructions adding the wait_table waitqueues in the
                   waitqueue-head before going to calculate the mask-retval. */
                __set_current_state(TASK_INTERRUPTIBLE);
-               if (!(file->f_op->poll(file, &wait_table) & POLLIN)) {
+               if (!(sock->ops->poll(file, sock, &wait_table) & POLLIN)) {
                        int timed_out;
                        if (timeout > max_timeout) {
                                /* JEJB/JSP 2/7/94
index 14cb7d50f7bef6282f1e386076fcb11b1b5820c0..999d90d254f150000961c0d25529119240e6cffc 100644 (file)
@@ -995,12 +995,15 @@ out_nfserr:
  * that the parent is still our parent and
  * that we are still hashed onto it..
  *
- * This is requied in case two processes race
+ * This is required in case two processes race
  * on removing (or moving) the same entry: the
  * parent lock will serialize them, but the
  * other process will be too late..
+ *
+ * Note that this nfsd_check_parent is different
+ * than the one in linux/include/dcache_func.h.
  */
-#define check_parent(dir, dentry) \
+#define nfsd_check_parent(dir, dentry) \
        ((dir) == (dentry)->d_parent->d_inode && !list_empty(&dentry->d_hash))
 
 /*
@@ -1079,8 +1082,8 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
        nfsd_double_down(&tdir->i_sem, &fdir->i_sem);
        err = -ENOENT;
        /* GAM3 check for parent changes after locking. */
-       if (check_parent(fdir, odentry) &&
-           check_parent(tdir, ndentry)) {
+       if (nfsd_check_parent(fdir, odentry) &&
+           nfsd_check_parent(tdir, ndentry)) {
 
                err = vfs_rename(fdir, odentry, tdir, ndentry);
                if (!err && EX_ISSYNC(tfhp->fh_export)) {
@@ -1168,7 +1171,7 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
                fhp->fh_locked = 1;
 
                err = -ENOENT;
-               if (check_parent(dirp, rdentry))
+               if (nfsd_check_parent(dirp, rdentry))
                        err = vfs_rmdir(dirp, rdentry);
 
                rdentry->d_count--;
index 7e147359d3ec5ace01f96f47545549261da56312..b549029d16985c64a3e37e1c0c34f18c501ada5f 100644 (file)
@@ -4,7 +4,6 @@
 /* Define to experiment with fitting everything into one 512MB HAE window.  */
 #define CIA_ONE_HAE_WINDOW 1
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <asm/compiler.h>
 
index c767183ee6895a0c4fe02cd63d1ab7d975954d19..644512cbab511ebe9c3c43fdaf60b72e47cd2b22 100644 (file)
@@ -1,7 +1,6 @@
 #ifndef __ALPHA_LCA__H__
 #define __ALPHA_LCA__H__
 
-#include <linux/config.h>
 #include <asm/system.h>
 #include <asm/compiler.h>
 
index 58a48f73566bcdeed0322003bf0c4fc1794e983e..577704129e8ba6257a59039d3d8c6d279b64cd20 100644 (file)
@@ -5,7 +5,6 @@
    One window per bus, that is.  */
 #define MCPCIA_ONE_HAE_WINDOW 1
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/pci.h>
 #include <asm/compiler.h>
index 5b205459b4921853845f12677a4f0c48ddc2fdd9..da53edc2276f4e4b7dcb56b9953958df56743a38 100644 (file)
@@ -1,7 +1,6 @@
 #ifndef __ALPHA_POLARIS__H__
 #define __ALPHA_POLARIS__H__
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <asm/compiler.h>
 
index 108de639397e178d409b4a91f5780cffce07724d..efdcd7d43b4d273528d04c16adbfbeed64bfe7c3 100644 (file)
@@ -1,7 +1,6 @@
 #ifndef __ALPHA_PYXIS__H__
 #define __ALPHA_PYXIS__H__
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <asm/compiler.h>
 
index c788cd8c905499b81b45e0d506ba7e7872cba837..14bc80e2db6d155d9447bc129c90ab73e51ca305 100644 (file)
@@ -1,7 +1,6 @@
 #ifndef __ALPHA_TSUNAMI__H__
 #define __ALPHA_TSUNAMI__H__
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <asm/compiler.h>
 
index 7b2d9ee95a44683b0546b43cc149d37de0c1a4e2..0b339a0c11e2d3764f37b63a7dfbe93703c33102 100644 (file)
@@ -26,6 +26,9 @@
 #define FOURPORT_FLAGS ASYNC_FOURPORT
 #define ACCENT_FLAGS 0
 #define BOCA_FLAGS 0
+#define RS_TABLE_SIZE  64
+#else
+#define RS_TABLE_SIZE  4
 #endif
        
 #define STD_SERIAL_PORT_DEFNS                  \
index aa9800003b980bb9aa99a2310841bce9c1c2c35d..e8506173629c479d78a907ad9572d7d49a3e12d1 100644 (file)
@@ -19,7 +19,7 @@ __hard_smp_processor_id(void)
 
 #ifdef __SMP__
 
-#include <linux/tasks.h>
+#include <linux/threads.h>
 
 struct cpuinfo_alpha {
        unsigned long loops_per_sec;
index 588c85894bc6c1c76f6bc7f1d451673027067913..79aec2cf6040befc6756db7fefe440c5b5d90566 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef __ASM_HARDIRQ_H
 #define __ASM_HARDIRQ_H
 
-#include <linux/tasks.h>
+#include <linux/threads.h>
 
 extern unsigned int local_irq_count[NR_CPUS];
 
index efb9c619d165787a4b9e23646ff5147698ab49ae..87299be508220d892e0621da7c5793cb289bf93f 100644 (file)
@@ -1,3 +1,4 @@
+#include <linux/config.h>
 
 #ifndef __ASSEMBLER__
 #define __IOMD(offset) (IO_IOMD_BASE + (offset >> 2))
index 0ac5f3eec776ed64ccd20c5e3eb75dd227bd8d96..1914385eb940b18630c783b17111d3779c21508d 100644 (file)
@@ -53,7 +53,7 @@ static char __initdata fpu_error = 0;
 static void __init copro_timeout(void)
 {
        fpu_error = 1;
-       timer_table[COPRO_TIMER].expires = jiffies+100;
+       timer_table[COPRO_TIMER].expires = jiffies+HZ;
        timer_active |= 1<<COPRO_TIMER;
        printk(KERN_ERR "387 failed: trying to reset\n");
        send_sig(SIGFPE, current, 1);
index 7b6d5f1e7e362971eb2bea3f98243ec3ccaa3cc0..34c82dbe01d08833afef179d7e694928b252f1f0 100644 (file)
@@ -18,7 +18,7 @@
 #include <asm/apic.h>
 #include <asm/page.h>
 #ifdef CONFIG_BIGMEM
-#include <linux/tasks.h>
+#include <linux/threads.h>
 #include <asm/kmap_types.h>
 #endif
 
index 05e82fc715d6ecb02737d8ce59d151632d0af21c..2232379ef9f23ac9f1c0fed259204faa3b25b3ff 100644 (file)
@@ -9,7 +9,7 @@
 #ifndef __ASM_MIPS_HARDIRQ_H
 #define __ASM_MIPS_HARDIRQ_H
 
-#include <linux/tasks.h>
+#include <linux/threads.h>
 
 extern unsigned int local_irq_count[NR_CPUS];
 
index b030a5e58ce255b69045bce4b36e0ba0cfbd9655..de3146b15a5c1e5597cb1753255b55ad340296af 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef __ASMPPC_GEMINI_SERIAL_H
 #define __ASMPPC_GEMINI_SERIAL_H
 
+#include <linux/config.h>
 #include <asm/gemini.h>
 
 /* Rate for the 24.576 Mhz clock for the onboard serial chip */
index 286cec3eb7abdd5a2cf2b72620382b4a371a01a8..f6309d6b228c82c17478b3f603f5278901339562 100644 (file)
@@ -6,7 +6,6 @@
  * Copyright (C) 1998 Paul Mackerras.
  */
 
-#include <linux/config.h>
 /*
  * PMU commands
  */
index ce43277c27e71d012afd872d42cb1ff698965497..38b651bc0046cb6b544afdc8da3bebc692fea1f1 100644 (file)
@@ -12,7 +12,6 @@
  * I don't know of any Super-H bugs yet.
  */
 
-#include <linux/config.h>
 #include <asm/processor.h>
 
 __initfunc(static void check_bugs(void))
index 39d412744ed683483022e60356309d40865259b9..de5512ce30e6f7196105149056004ffe1c5d743c 100644 (file)
@@ -5,6 +5,7 @@
  * ELF register definitions..
  */
 
+#include <linux/config.h>
 #include <asm/ptrace.h>
 #include <asm/user.h>
 #include <asm/byteorder.h>
index 11a7a866613b18df6b2b4c9d15c9a73d158c36df..bf1ea66d301d8062e833f985c88be9cb93a34cb9 100644 (file)
@@ -12,7 +12,7 @@
 #include <asm/page.h>
 #include <asm/ap1000/apservice.h>
 #include <asm/ap1000/apbif.h>
-#include <linux/tasks.h>
+#include <linux/threads.h>
 
 /*
  * Macros for accessing I/O registers.
index 5763a689aa41c58850413c59a1e59b3be4307039..cb9a213a3504969c023ff4f5043106ba50d65b4c 100644 (file)
@@ -237,7 +237,6 @@ typedef struct audio_device {
 
 #ifdef __KERNEL__
 
-#include <linux/types.h>
 #include <linux/fs.h>
 #include <linux/tqueue.h>
 #include <linux/wait.h>
index 5763a689aa41c58850413c59a1e59b3be4307039..cb9a213a3504969c023ff4f5043106ba50d65b4c 100644 (file)
@@ -237,7 +237,6 @@ typedef struct audio_device {
 
 #ifdef __KERNEL__
 
-#include <linux/types.h>
 #include <linux/fs.h>
 #include <linux/tqueue.h>
 #include <linux/wait.h>
index d58d288d9d3e143d8ef431585e9174ee36e46040..784a14b782c42b4caf1b42aedb5dad56736618c7 100644 (file)
@@ -7,6 +7,7 @@
 #ifndef _ASM_SPARC64_DMA_H
 #define _ASM_SPARC64_DMA_H
 
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 
index 6ab9ef7ec7c25cfd9347b73aff7f29f9107d9916..42e395d73a097ddf90eaab3f0c8a02bb0c334481 100644 (file)
@@ -6,7 +6,7 @@
 #ifndef __SPARC64_HARDIRQ_H
 #define __SPARC64_HARDIRQ_H
 
-#include <linux/tasks.h>
+#include <linux/threads.h>
 
 #ifndef __SMP__
 extern unsigned int local_irq_count;
index d07d1e61a6fe187184095000e87e2fcd45279277..69f9730eb9558d873869975fc172fd85315740e1 100644 (file)
@@ -4,7 +4,7 @@
  *     cd1400.h  -- cd1400 UART hardware info.
  *
  *     Copyright (C) 1996-1998  Stallion Technologies (support@stallion.oz.au).
- *     Copyright (C) 1994-1996  Greg Ungerer (gerg@stallion.oz.au).
+ *     Copyright (C) 1994-1996  Greg Ungerer.
  *
  *     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
index 2180e433023c2ac6ae43149b7fc9660520c9213f..b7576643d63bf4636fb42babfc5851a61ac3835c 100644 (file)
@@ -4,7 +4,7 @@
  *     cdk.h  -- CDK interface definitions.
  *
  *     Copyright (C) 1996-1998  Stallion Technologies (support@stallion.oz.au).
- *     Copyright (C) 1994-1996  Greg Ungerer (gerg@stallion.oz.au).
+ *     Copyright (C) 1994-1996  Greg Ungerer.
  *
  *     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
index 066888599ae167b8625885f16a9b28c567e4b7a8..84ef9b2b03bc3b3d4870e77f8574e1e955fecf2f 100644 (file)
@@ -4,7 +4,7 @@
  *     comstats.h  -- Serial Port Stats.
  *
  *     Copyright (C) 1996-1998  Stallion Technologies (support@stallion.oz.au).
- *     Copyright (C) 1994-1996  Greg Ungerer (gerg@stallion.oz.au).
+ *     Copyright (C) 1994-1996  Greg Ungerer.
  *
  *     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
index a3bd49f1f4c469c5bdfbb1c7bb578debbaa230d0..4b5141d401fd810840f7c7e65ab4c1f2af5d13b2 100644 (file)
@@ -169,7 +169,6 @@ struct i2o_device
        char dev_name[8];               /* linux /dev name if available */
 };
 
-#ifdef CONFIG_I2O_PCI_MODULE
 /*
  *     Resource data for each PCI I2O controller
  */            
@@ -177,7 +176,7 @@ struct i2o_pci
 {
        int irq;
 };
-#endif
+
 
 /*
  *     Each I2O controller has one of these objects
index e55728c94f022d5fd6d61517b8713153afae99bb..cf5f367750c9d5d76ac38d7a2f69d4d8a0b4dbb9 100644 (file)
@@ -87,11 +87,16 @@ extern int allocate_resource(struct resource *root, struct resource *new,
 
 /* Convenience shorthand with allocation */
 #define request_region(start,n,name)   __request_region(&ioport_resource, (start), (n), (name))
+#define request_mem_region(start,n,name) __request_region(&iomem_resource, (start), (n), (name))
+
 extern struct resource * __request_region(struct resource *, unsigned long start, unsigned long n, const char *name);
 
 /* Compatibility cruft */
 #define check_region(start,n)  __check_region(&ioport_resource, (start), (n))
 #define release_region(start,n)        __release_region(&ioport_resource, (start), (n))
+#define check_mem_region(start,n)      __check_region(&iomem_resource, (start), (n))
+#define release_mem_region(start,n)    __release_region(&iomem_resource, (start), (n))
+
 extern int __check_region(struct resource *, unsigned long, unsigned long);
 extern void __release_region(struct resource *, unsigned long, unsigned long);
 
index cc9831b44f394f50ee6b54b4767376017143d16b..e8a2709f66fbc78895a5b912fcfc121bc087f4dd 100644 (file)
@@ -4,7 +4,7 @@
  *     istallion.h  -- stallion intelligent multiport serial driver.
  *
  *     Copyright (C) 1996-1998  Stallion Technologies (support@stallion.oz.au).
- *     Copyright (C) 1994-1996  Greg Ungerer (gerg@stallion.oz.au).
+ *     Copyright (C) 1994-1996  Greg Ungerer.
  *
  *     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
@@ -70,9 +70,15 @@ typedef struct {
        long                    pgrp;
        unsigned int            rxmarkmsk;
        struct tty_struct       *tty;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+       struct wait_queue       *open_wait;
+       struct wait_queue       *close_wait;
+       struct wait_queue       *raw_wait;
+#else
        wait_queue_head_t       open_wait;
        wait_queue_head_t       close_wait;
        wait_queue_head_t       raw_wait;
+#endif
        struct tq_struct        tqhangup;
        struct termios          normaltermios;
        struct termios          callouttermios;
index 33a969a9835fd6373f7bab6f582f7074510b26ea..b687d7558d41b989deaeab8a6ce6e37700e10bd7 100644 (file)
@@ -108,6 +108,4 @@ static inline void wait_on_page(struct page * page)
                ___wait_on_page(page);
 }
 
-extern void update_vm_cache(struct inode *, unsigned long, const char *, int);
-
 #endif
index 2f45e1e1564c10b2d6499f0ab01333d087c85d54..146c435fa47c133dab8a8d673a917d03582d93cc 100644 (file)
 #define PCI_DEVICE_ID_MYLEX_DAC960P_V4 0x0010
 #define PCI_DEVICE_ID_MYLEX_DAC960P_V5 0x0020
 
+#define PCI_VENDOR_ID_MYLEX            0x1069
+#define PCI_DEVICE_ID_MYLEX_DAC960P_V2 0x0001
+#define PCI_DEVICE_ID_MYLEX_DAC960P_V3 0x0002
+#define PCI_DEVICE_ID_MYLEX_DAC960P_V4 0x0010
+#define PCI_DEVICE_ID_MYLEX_DAC960P_V5 0x0020
+
 #define PCI_VENDOR_ID_PICOP            0x1066
 #define PCI_DEVICE_ID_PICOP_PT86C52X   0x0001
 #define PCI_DEVICE_ID_PICOP_PT80C524   0x8002
 #define PCI_DEVICE_ID_INTERPHASE_5526  0x0004
 #define PCI_DEVICE_ID_INTERPHASE_55x6  0x0005
 
+#define PCI_VENDOR_ID_INTERPHASE               0x107e
+#define PCI_DEVICE_ID_INTERPHASE_5526  0x0004
+#define PCI_DEVICE_ID_INTERPHASE_55x6  0x0005
+
 /*
  * The PCI interface treats multi-function devices as independent
  * devices.  The slot/function address of each device is encoded
@@ -1478,7 +1488,9 @@ struct pci_ops {
 void pcibios_init(void);
 void pcibios_fixup_bus(struct pci_bus *);
 char *pcibios_setup (char *str);
-int pcibios_assign_resource(struct pci_dev *, int i);
+void pcibios_update_resource(struct pci_dev *, struct resource *,
+                            struct resource *, int);
+void pcibios_update_irq(struct pci_dev *, int irq);
 
 
 /* Backward compatibility, don't use in new code! */
@@ -1520,6 +1532,12 @@ struct pci_dev *pci_find_class (unsigned int class, struct pci_dev *from);
 struct pci_dev *pci_find_slot (unsigned int bus, unsigned int devfn);
 int pci_find_capability (struct pci_dev *dev, int cap);
 
+int pci_claim_resource(struct pci_dev *, int);
+void pci_assign_unassigned_resources(u32 min_io, u32 min_mem);
+void pci_set_bus_ranges(void);
+void pci_fixup_irqs(u8 (*)(struct pci_dev *, u8 *),
+                   int (*)(struct pci_dev *, u8, u8));
+
 #define PCI_ANY_ID (~0)
 
 int pci_read_config_byte(struct pci_dev *dev, int where, u8 *val);
index b06ac1dfbf885ca6d8014784c3bf04a999551abc..37dc527e2a7adc10be003821527a577df12a8307 100644 (file)
@@ -19,6 +19,7 @@
  * For definitions of the flags field, see tty.h
  */
 
+#include <linux/config.h>
 #include <linux/termios.h>
 #include <linux/tqueue.h>
 #include <linux/wait.h>
index 94f5a173449debde949ded82a5e08e4b79ae1581..a4f6e22781c1a778f9d3467eb46a30a57a76926e 100644 (file)
@@ -4,7 +4,7 @@
  *     stallion.h  -- stallion multiport serial driver.
  *
  *     Copyright (C) 1996-1998  Stallion Technologies (support@stallion.oz.au).
- *     Copyright (C) 1994-1996  Greg Ungerer (gerg@stallion.oz.au).
+ *     Copyright (C) 1994-1996  Greg Ungerer.
  *
  *     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
@@ -95,8 +95,13 @@ typedef struct stlport {
        unsigned long           hwid;
        void                    *uartp;
        struct tty_struct       *tty;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+       struct wait_queue       *open_wait;
+       struct wait_queue       *close_wait;
+#else
        wait_queue_head_t       open_wait;
        wait_queue_head_t       close_wait;
+#endif
        struct termios          normaltermios;
        struct termios          callouttermios;
        struct tq_struct        tqueue;
index edf1ff28f44fd4c888c3a8bd179e2f7207b6c6ec..9f94fbaab2cce9b4c2391dda5f52b59100b8f9db 100644 (file)
@@ -344,6 +344,7 @@ extern int rs_init(void);
 extern int lp_init(void);
 extern int pty_init(void);
 extern int tty_init(void);
+extern int ip2_init(void);
 extern int pcxe_init(void);
 extern int pc_init(void);
 extern int vcs_init(void);
diff --git a/include/pcmcia/bulkmem.h b/include/pcmcia/bulkmem.h
new file mode 100644 (file)
index 0000000..634693c
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * Definitions for bulk memory services
+ *
+ * bulkmem.h 1.10 1999/08/28 04:12:33
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ * bulkmem.h 1.3 1995/05/27 04:49:49
+ */
+
+#ifndef _LINUX_BULKMEM_H
+#define _LINUX_BULKMEM_H
+
+/* For GetFirstRegion and GetNextRegion */
+typedef struct region_info_t {
+    u_int              Attributes;
+    u_int              CardOffset;
+    u_int              RegionSize;
+    u_int              AccessSpeed;
+    u_int              BlockSize;
+    u_int              PartMultiple;
+    u_char             JedecMfr, JedecInfo;
+    memory_handle_t    next;
+} region_info_t;
+
+#define REGION_TYPE            0x0001
+#define REGION_TYPE_CM         0x0000
+#define REGION_TYPE_AM         0x0001
+#define REGION_PREFETCH                0x0008
+#define REGION_CACHEABLE       0x0010
+#define REGION_BAR_MASK                0xe000
+#define REGION_BAR_SHIFT       13
+
+/* For OpenMemory */
+typedef struct open_mem_t {
+    u_int              Attributes;
+    u_int              Offset;
+} open_mem_t;
+
+/* Attributes for OpenMemory */
+#define MEMORY_TYPE            0x0001
+#define MEMORY_TYPE_CM         0x0000
+#define MEMORY_TYPE_AM         0x0001
+#define MEMORY_EXCLUSIVE       0x0002
+#define MEMORY_PREFETCH                0x0008
+#define MEMORY_CACHEABLE       0x0010
+#define MEMORY_BAR_MASK                0xe000
+#define MEMORY_BAR_SHIFT       13
+
+typedef struct eraseq_entry_t {
+    memory_handle_t    Handle;
+    u_char             State;
+    u_int              Size;
+    u_int              Offset;
+    void               *Optional;
+} eraseq_entry_t;
+
+typedef struct eraseq_hdr_t {
+    int                        QueueEntryCnt;
+    eraseq_entry_t     *QueueEntryArray;
+} eraseq_hdr_t;
+
+#define ERASE_QUEUED           0x00
+#define ERASE_IN_PROGRESS(n)   (((n) > 0) && ((n) < 0x80))
+#define ERASE_IDLE             0xff
+#define ERASE_PASSED           0xe0
+#define ERASE_FAILED           0xe1
+
+#define ERASE_MISSING          0x80
+#define ERASE_MEDIA_WRPROT     0x84
+#define ERASE_NOT_ERASABLE     0x85
+#define ERASE_BAD_OFFSET       0xc1
+#define ERASE_BAD_TECH         0xc2
+#define ERASE_BAD_SOCKET       0xc3
+#define ERASE_BAD_VCC          0xc4
+#define ERASE_BAD_VPP          0xc5
+#define ERASE_BAD_SIZE         0xc6
+
+/* For CopyMemory */
+typedef struct copy_op_t {
+    u_int              Attributes;
+    u_int              SourceOffset;
+    u_int              DestOffset;
+    u_int              Count;
+} copy_op_t;
+
+/* For ReadMemory and WriteMemory */
+typedef struct mem_op_t {
+    u_int      Attributes;
+    u_int      Offset;
+    u_int      Count;
+} mem_op_t;
+
+#define MEM_OP_BUFFER          0x01
+#define MEM_OP_BUFFER_USER     0x00
+#define MEM_OP_BUFFER_KERNEL   0x01
+#define MEM_OP_DISABLE_ERASE   0x02
+#define MEM_OP_VERIFY          0x04
+
+/* For RegisterMTD */
+typedef struct mtd_reg_t {
+    u_int      Attributes;
+    u_int      Offset;
+    u_long     MediaID;
+} mtd_reg_t;
+
+/*
+ *  Definitions for MTD requests
+ */
+
+typedef struct mtd_request_t {
+    u_int      SrcCardOffset;
+    u_int      DestCardOffset;
+    u_int      TransferLength;
+    u_int      Function;
+    u_long     MediaID;
+    u_int      Status;
+    u_int      Timeout;
+} mtd_request_t;
+
+/* Fields in MTD Function */
+#define MTD_REQ_ACTION         0x003
+#define MTD_REQ_ERASE          0x000
+#define MTD_REQ_READ           0x001
+#define MTD_REQ_WRITE          0x002
+#define MTD_REQ_COPY           0x003
+#define MTD_REQ_NOERASE                0x004
+#define MTD_REQ_VERIFY         0x008
+#define MTD_REQ_READY          0x010
+#define MTD_REQ_TIMEOUT                0x020
+#define MTD_REQ_LAST           0x040
+#define MTD_REQ_FIRST          0x080
+#define MTD_REQ_KERNEL         0x100
+
+/* Status codes */
+#define MTD_WAITREQ    0x00
+#define MTD_WAITTIMER  0x01
+#define MTD_WAITRDY    0x02
+#define MTD_WAITPOWER  0x03
+
+/*
+ *  Definitions for MTD helper functions
+ */
+
+/* For MTDModifyWindow */
+typedef struct mtd_mod_win_t {
+    u_int      Attributes;
+    u_int      AccessSpeed;
+    u_int      CardOffset;
+} mtd_mod_win_t;
+
+/* For MTDSetVpp */
+typedef struct mtd_vpp_req_t {
+    u_char     Vpp1, Vpp2;
+} mtd_vpp_req_t;
+
+/* For MTDRDYMask */
+typedef struct mtd_rdy_req_t {
+    u_int      Mask;
+} mtd_rdy_req_t;
+
+enum mtd_helper {
+    MTDRequestWindow, MTDModifyWindow, MTDReleaseWindow,
+    MTDSetVpp, MTDRDYMask
+};
+
+#ifdef IN_CARD_SERVICES
+extern int MTDHelperEntry(int func, void *a1, void *a2);
+#else
+extern int MTDHelperEntry(int func, ...);
+#endif
+
+#endif /* _LINUX_BULKMEM_H */
diff --git a/include/pcmcia/bus_ops.h b/include/pcmcia/bus_ops.h
new file mode 100644 (file)
index 0000000..56f0dd9
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * bus_ops.h 1.6 1999/08/28 04:12:33
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_BUS_OPS_H
+#define _LINUX_BUS_OPS_H
+
+typedef struct bus_operations {
+    void       *priv;
+    u32                (*b_in)(void *bus, u32 port, s32 sz);
+    void       (*b_ins)(void *bus, u32 port, void *buf,
+                        u32 count, s32 sz);
+    void       (*b_out)(void *bus, u32 val, u32 port, s32 sz);
+    void       (*b_outs)(void *bus, u32 port, void *buf,
+                         u32 count, s32 sz);
+    void       *(*b_ioremap)(void *bus, u_long ofs, u_long sz);
+    void       (*b_iounmap)(void *bus, void *addr);
+    u32                (*b_read)(void *bus, void *addr, s32 sz);
+    void       (*b_write)(void *bus, u32 val, void *addr, s32 sz);
+    void       (*b_copy_from)(void *bus, void *d, void *s, u32 count);
+    void       (*b_copy_to)(void *bus, void *d, void *s, u32 count);
+    int                (*b_request_irq)(void *bus, u_int irq,
+                                void (*handler)(int, void *,
+                                                struct pt_regs *),
+                                u_long flags, const char *device,
+                                void *dev_id);
+    void       (*b_free_irq)(void *bus, u_int irq, void *dev_id);
+} bus_operations;
+
+#ifdef CONFIG_VIRTUAL_BUS
+
+#define bus_inb(b,p)           (b)->b_in((b),(p),0)
+#define bus_inw(b,p)           (b)->b_in((b),(p),1)
+#define bus_inl(b,p)           (b)->b_in((b),(p),2)
+#define bus_inw_ns(b,p)                (b)->b_in((b),(p),-1)
+#define bus_inl_ns(b,p)                (b)->b_in((b),(p),-2)
+
+#define bus_insb(b,p,a,c)      (b)->b_ins((b),(p),(a),(c),0)
+#define bus_insw(b,p,a,c)      (b)->b_ins((b),(p),(a),(c),1)
+#define bus_insl(b,p,a,c)      (b)->b_ins((b),(p),(a),(c),2)
+#define bus_insw_ns(b,p,a,c)   (b)->b_ins((b),(p),(a),(c),-1)
+#define bus_insl_ns(b,p,a,c)   (b)->b_ins((b),(p),(a),(c),-2)
+
+#define bus_outb(b,v,p)                (b)->b_out((b),(v),(p),0)
+#define bus_outw(b,v,p)                (b)->b_out((b),(v),(p),1)
+#define bus_outl(b,v,p)                (b)->b_out((b),(v),(p),2)
+#define bus_outw_ns(b,v,p)     (b)->b_out((b),(v),(p),-1)
+#define bus_outl_ns(b,v,p)     (b)->b_out((b),(v),(p),-2)
+
+#define bus_outsb(b,p,a,c)     (b)->b_outs((b),(p),(a),(c),0)
+#define bus_outsw(b,p,a,c)     (b)->b_outs((b),(p),(a),(c),1)
+#define bus_outsl(b,p,a,c)     (b)->b_outs((b),(p),(a),(c),2)
+#define bus_outsw_ns(b,p,a,c)  (b)->b_outs((b),(p),(a),(c),-1)
+#define bus_outsl_ns(b,p,a,c)  (b)->b_outs((b),(p),(a),(c),-2)
+
+#define bus_readb(b,a)         (b)->b_read((b),(a),0)
+#define bus_readw(b,a)         (b)->b_read((b),(a),1)
+#define bus_readl(b,a)         (b)->b_read((b),(a),2)
+#define bus_readw_ns(b,a)      (b)->b_read((b),(a),-1)
+#define bus_readl_ns(b,a)      (b)->b_read((b),(a),-2)
+
+#define bus_writeb(b,v,a)      (b)->b_write((b),(v),(a),0)
+#define bus_writew(b,v,a)      (b)->b_write((b),(v),(a),1)
+#define bus_writel(b,v,a)      (b)->b_write((b),(v),(a),2)
+#define bus_writew_ns(b,v,a)   (b)->b_write((b),(v),(a),-1)
+#define bus_writel_ns(b,v,a)   (b)->b_write((b),(v),(a),-2)
+
+#define bus_ioremap(b,s,n)     (b)->b_ioremap((b),(s),(n))
+#define bus_iounmap(b,a)       (b)->b_iounmap((b),(a))
+#define bus_memcpy_fromio(b,d,s,n) (b)->b_copy_from((b),(d),(s),(n))
+#define bus_memcpy_toio(b,d,s,n) (b)->b_copy_to((b),(d),(s),(n))
+
+#define bus_request_irq(b,i,h,f,n,d) \
+                               (b)->b_request_irq((b),(i),(h),(f),(n),(d))
+#define bus_free_irq(b,i,d)    (b)->b_free_irq((b),(i),(d))
+
+#else
+
+#define bus_inb(b,p)           inb(p)
+#define bus_inw(b,p)           inw(p)
+#define bus_inl(b,p)           inl(p)
+#define bus_inw_ns(b,p)                inw_ns(p)
+#define bus_inl_ns(b,p)                inl_ns(p)
+
+#define bus_insb(b,p,a,c)      insb(p,a,c)
+#define bus_insw(b,p,a,c)      insw(p,a,c)
+#define bus_insl(b,p,a,c)      insl(p,a,c)
+#define bus_insw_ns(b,p,a,c)   insw_ns(p,a,c)
+#define bus_insl_ns(b,p,a,c)   insl_ns(p,a,c)
+
+#define bus_outb(b,v,p)                outb(b,v,p)
+#define bus_outw(b,v,p)                outw(b,v,p)
+#define bus_outl(b,v,p)                outl(b,v,p)
+#define bus_outw_ns(b,v,p)     outw_ns(b,v,p)
+#define bus_outl_ns(b,v,p)     outl_ns(b,v,p)
+
+#define bus_outsb(b,p,a,c)     outsb(p,a,c)
+#define bus_outsw(b,p,a,c)     outsw(p,a,c)
+#define bus_outsl(b,p,a,c)     outsl(p,a,c)
+#define bus_outsw_ns(b,p,a,c)  outsw_ns(p,a,c)
+#define bus_outsl_ns(b,p,a,c)  outsl_ns(p,a,c)
+
+#define bus_readb(b,a)         readb(a)
+#define bus_readw(b,a)         readw(a)
+#define bus_readl(b,a)         readl(a)
+#define bus_readw_ns(b,a)      readw_ns(a)
+#define bus_readl_ns(b,a)      readl_ns(a)
+
+#define bus_writeb(b,v,a)      writeb(v,a)
+#define bus_writew(b,v,a)      writew(v,a)
+#define bus_writel(b,v,a)      writel(v,a)
+#define bus_writew_ns(b,v,a)   writew_ns(v,a)
+#define bus_writel_ns(b,v,a)   writel_ns(v,a)
+
+#define bus_ioremap(b,s,n)     ioremap(s,n)
+#define bus_iounmap(b,a)       iounmap(a)
+#define bus_memcpy_fromio(b,d,s,n) memcpy_fromio(d,s,n)
+#define bus_memcpy_toio(b,d,s,n) memcpy_toio(d,s,n)
+
+#define bus_request_irq(b,i,h,f,n,d) request_irq((i),(h),(f),(n),(d))
+#define bus_free_irq(b,i,d)    free_irq((i),(d))
+
+#endif /* CONFIG_VIRTUAL_BUS */
+
+#endif /* _LINUX_BUS_OPS_H */
diff --git a/include/pcmcia/ciscode.h b/include/pcmcia/ciscode.h
new file mode 100644 (file)
index 0000000..32915c1
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * ciscode.h 1.38 1999/08/28 04:12:32
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_CISCODE_H
+#define _LINUX_CISCODE_H
+
+/* Manufacturer and Product ID codes */
+
+#define MANFID_3COM                    0x0101
+#define PRODID_3COM_3CXEM556           0x0035
+#define PRODID_3COM_3CCFEM556          0x0556
+#define PRODID_3COM_3C562              0x0562
+
+#define MANFID_ACCTON                  0x01bf
+#define PRODID_ACCTON_EN2226           0x010a
+
+#define MANFID_ADAPTEC                 0x012f
+#define PRODID_ADAPTEC_SCSI            0x0001
+
+#define MANFID_ATT                     0xffff
+#define PRODID_ATT_KIT                 0x0100
+
+#define MANFID_CONTEC                  0xc001
+
+#define MANFID_FUJITSU                 0x0004
+#define PRODID_FUJITSU_MBH10302                0x0004
+#define PRODID_FUJITSU_MBH10304                0x1003
+#define PRODID_FUJITSU_LA501           0x2000
+
+#define MANFID_IBM                     0x00a4
+#define PRODID_IBM_HOME_AND_AWAY       0x002e
+
+#define MANFID_INTEL                   0x0089
+#define PRODID_INTEL_DUAL_RS232                0x0301
+#define PRODID_INTEL_2PLUS             0x8422
+
+#define MANFID_LINKSYS                 0x0143
+#define PRODID_LINKSYS_PCMLM28         0xc0ab
+#define PRODID_LINKSYS_3400            0x3341
+
+#define MANFID_MEGAHERTZ               0x0102
+#define PRODID_MEGAHERTZ_VARIOUS       0x0000
+#define PRODID_MEGAHERTZ_EM3288                0x0006
+
+#define MANFID_MACNICA                 0xc00b
+
+#define MANFID_MOTOROLA                        0x0109
+#define PRODID_MOTOROLA_MARINER                0x0501
+
+#define MANFID_NATINST                 0x010b
+#define PRODID_NATINST_QUAD_RS232      0xd180
+
+#define MANFID_NEW_MEDIA               0x0057
+
+#define MANFID_OLICOM                  0x0121
+#define PRODID_OLICOM_OC2231           0x3122
+#define PRODID_OLICOM_OC2232           0x3222
+
+#define MANFID_OMEGA                   0x0137
+#define PRODID_OMEGA_QSP_100           0x0025
+
+#define MANFID_OSITECH                 0x0140
+#define PRODID_OSITECH_JACK_144                0x0001
+#define PRODID_OSITECH_JACK_288                0x0002
+#define PRODID_OSITECH_JACK_336                0x0007
+#define PRODID_OSITECH_SEVEN           0x0008
+
+#define MANFID_PSION                   0x016c
+
+#define MANFID_QUATECH                 0x0137
+#define PRODID_QUATECH_SPP100          0x0003
+#define PRODID_QUATECH_DUAL_RS232      0x0012
+#define PRODID_QUATECH_DUAL_RS232_D1   0x0007
+#define PRODID_QUATECH_QUAD_RS232      0x001b
+
+#define MANFID_SMC                     0x0108
+#define PRODID_SMC_ETHER               0x0105
+
+#define MANFID_SOCKET                  0x0104
+#define PRODID_SOCKET_DUAL_RS232       0x0006
+#define PRODID_SOCKET_LPE              0x000d
+
+#define MANFID_SUNDISK                 0x0045
+
+#define MANFID_TDK                     0x0105
+
+#define MANFID_XIRCOM                  0x0105
+
+#endif /* _LINUX_CISCODE_H */
diff --git a/include/pcmcia/cisreg.h b/include/pcmcia/cisreg.h
new file mode 100644 (file)
index 0000000..16c3dee
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * cisreg.h 1.13 1999/08/28 04:12:32
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_CISREG_H
+#define _LINUX_CISREG_H
+
+/* Offsets from ConfigBase for CIS registers */
+#define CISREG_COR             0x00
+#define CISREG_CCSR            0x02
+#define CISREG_PRR             0x04
+#define CISREG_SCR             0x06
+#define CISREG_ESR             0x08
+#define CISREG_IOBASE_0                0x0a
+#define CISREG_IOBASE_1                0x0c
+#define CISREG_IOBASE_2                0x0e
+#define CISREG_IOBASE_3                0x10
+#define CISREG_IOSIZE          0x12
+
+/*
+ * Configuration Option Register
+ */
+#define COR_CONFIG_MASK                0x3f
+#define COR_MFC_CONFIG_MASK    0x38
+#define COR_FUNC_ENA           0x01
+#define COR_ADDR_DECODE                0x02
+#define COR_IREQ_ENA           0x04
+#define COR_LEVEL_REQ          0x40
+#define COR_SOFT_RESET         0x80
+
+/*
+ * Card Configuration and Status Register
+ */
+#define CCSR_INTR_ACK          0x01
+#define CCSR_INTR_PENDING      0x02
+#define CCSR_POWER_DOWN                0x04
+#define CCSR_AUDIO_ENA         0x08
+#define CCSR_IOIS8             0x20
+#define CCSR_SIGCHG_ENA                0x40
+#define CCSR_CHANGED           0x80
+
+/*
+ * Pin Replacement Register
+ */
+#define PRR_WP_STATUS          0x01
+#define PRR_READY_STATUS       0x02
+#define PRR_BVD2_STATUS                0x04
+#define PRR_BVD1_STATUS                0x08
+#define PRR_WP_EVENT           0x10
+#define PRR_READY_EVENT                0x20
+#define PRR_BVD2_EVENT         0x40
+#define PRR_BVD1_EVENT         0x80
+
+/*
+ * Socket and Copy Register
+ */
+#define SCR_SOCKET_NUM         0x0f
+#define SCR_COPY_NUM           0x70
+
+/*
+ * Extended Status Register
+ */
+#define ESR_REQ_ATTN_ENA       0x01
+#define ESR_REQ_ATTN           0x10
+
+/*
+ * CardBus Function Status Registers
+ */
+#define CBFN_EVENT             0x00
+#define CBFN_MASK              0x04
+#define CBFN_STATE             0x08
+#define CBFN_FORCE             0x0c
+
+/*
+ * These apply to all the CardBus function registers
+ */
+#define CBFN_WP                        0x0001
+#define CBFN_READY             0x0002
+#define CBFN_BVD2              0x0004
+#define CBFN_BVD1              0x0008
+#define CBFN_GWAKE             0x0010
+#define CBFN_INTR              0x8000
+
+/*
+ * Extra bits in the Function Event Mask Register
+ */
+#define FEMR_BAM_ENA           0x0020
+#define FEMR_PWM_ENA           0x0040
+#define FEMR_WKUP_MASK         0x4000
+
+#endif /* _LINUX_CISREG_H */
diff --git a/include/pcmcia/cistpl.h b/include/pcmcia/cistpl.h
new file mode 100644 (file)
index 0000000..2006653
--- /dev/null
@@ -0,0 +1,583 @@
+/*
+ * cistpl.h 1.30 1999/08/28 04:12:32
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_CISTPL_H
+#define _LINUX_CISTPL_H
+
+#define CISTPL_NULL            0x00
+#define CISTPL_DEVICE          0x01
+#define CISTPL_LONGLINK_CB     0x02
+#define CISTPL_CONFIG_CB       0x04
+#define CISTPL_CFTABLE_ENTRY_CB        0x05
+#define CISTPL_LONGLINK_MFC    0x06
+#define CISTPL_BAR             0x07
+#define CISTPL_CHECKSUM                0x10
+#define CISTPL_LONGLINK_A      0x11
+#define CISTPL_LONGLINK_C      0x12
+#define CISTPL_LINKTARGET      0x13
+#define CISTPL_NO_LINK         0x14
+#define CISTPL_VERS_1          0x15
+#define CISTPL_ALTSTR          0x16
+#define CISTPL_DEVICE_A                0x17
+#define CISTPL_JEDEC_C         0x18
+#define CISTPL_JEDEC_A         0x19
+#define CISTPL_CONFIG          0x1a
+#define CISTPL_CFTABLE_ENTRY   0x1b
+#define CISTPL_DEVICE_OC       0x1c
+#define CISTPL_DEVICE_OA       0x1d
+#define CISTPL_DEVICE_GEO      0x1e
+#define CISTPL_DEVICE_GEO_A    0x1f
+#define CISTPL_MANFID          0x20
+#define CISTPL_FUNCID          0x21
+#define CISTPL_FUNCE           0x22
+#define CISTPL_SWIL            0x23
+#define CISTPL_END             0xff
+/* Layer 2 tuples */
+#define CISTPL_VERS_2          0x40
+#define CISTPL_FORMAT          0x41
+#define CISTPL_GEOMETRY                0x42
+#define CISTPL_BYTEORDER       0x43
+#define CISTPL_DATE            0x44
+#define CISTPL_BATTERY         0x45
+/* Layer 3 tuples */
+#define CISTPL_ORG             0x46
+
+typedef struct cistpl_longlink_t {
+    u_int      addr;
+} cistpl_longlink_t;
+
+typedef struct cistpl_checksum_t {
+    u_short    addr;
+    u_short    len;
+    u_char     sum;
+} cistpl_checksum_t;
+
+#define CISTPL_MAX_FUNCTIONS   8
+#define CISTPL_MFC_ATTR                0x00
+#define CISTPL_MFC_COMMON      0x01
+
+typedef struct cistpl_longlink_mfc_t {
+    u_char     nfn;
+    struct {
+       u_char  space;
+       u_int   addr;
+    } fn[CISTPL_MAX_FUNCTIONS];
+} cistpl_longlink_mfc_t;
+
+#define CISTPL_MAX_ALTSTR_STRINGS      4
+
+typedef struct cistpl_altstr_t {
+    u_char     ns;
+    u_char     ofs[CISTPL_MAX_ALTSTR_STRINGS];
+    char       str[254];
+} cistpl_altstr_t;
+
+#define CISTPL_DTYPE_NULL      0x00
+#define CISTPL_DTYPE_ROM       0x01
+#define CISTPL_DTYPE_OTPROM    0x02
+#define CISTPL_DTYPE_EPROM     0x03
+#define CISTPL_DTYPE_EEPROM    0x04
+#define CISTPL_DTYPE_FLASH     0x05
+#define CISTPL_DTYPE_SRAM      0x06
+#define CISTPL_DTYPE_DRAM      0x07
+#define CISTPL_DTYPE_FUNCSPEC  0x0d
+#define CISTPL_DTYPE_EXTEND    0x0e
+
+#define CISTPL_MAX_DEVICES     4
+
+typedef struct cistpl_device_t {
+    u_char     ndev;
+    struct {
+       u_char  type;
+       u_char  wp;
+       u_int   speed;
+       u_int   size;
+    } dev[CISTPL_MAX_DEVICES];
+} cistpl_device_t;
+
+#define CISTPL_DEVICE_MWAIT    0x01
+#define CISTPL_DEVICE_3VCC     0x02
+
+typedef struct cistpl_device_o_t {
+    u_char             flags;
+    cistpl_device_t    device;
+} cistpl_device_o_t;
+
+#define CISTPL_VERS_1_MAX_PROD_STRINGS 4
+
+typedef struct cistpl_vers_1_t {
+    u_char     major;
+    u_char     minor;
+    u_char     ns;
+    u_char     ofs[CISTPL_VERS_1_MAX_PROD_STRINGS];
+    char       str[254];
+} cistpl_vers_1_t;
+
+typedef struct cistpl_jedec_t {
+    u_char     nid;
+    struct {
+       u_char  mfr;
+       u_char  info;
+    } id[CISTPL_MAX_DEVICES];
+} cistpl_jedec_t;
+
+typedef struct cistpl_manfid_t {
+    u_short    manf;
+    u_short    card;
+} cistpl_manfid_t;
+
+#define CISTPL_FUNCID_MULTI    0x00
+#define CISTPL_FUNCID_MEMORY   0x01
+#define CISTPL_FUNCID_SERIAL   0x02
+#define CISTPL_FUNCID_PARALLEL 0x03
+#define CISTPL_FUNCID_FIXED    0x04
+#define CISTPL_FUNCID_VIDEO    0x05
+#define CISTPL_FUNCID_NETWORK  0x06
+#define CISTPL_FUNCID_AIMS     0x07
+#define CISTPL_FUNCID_SCSI     0x08
+
+#define CISTPL_SYSINIT_POST    0x01
+#define CISTPL_SYSINIT_ROM     0x02
+
+typedef struct cistpl_funcid_t {
+    u_char     func;
+    u_char     sysinit;
+} cistpl_funcid_t;
+
+typedef struct cistpl_funce_t {
+    u_char     type;
+    u_char     data[0];
+} cistpl_funce_t;
+
+/*======================================================================
+
+    Modem Function Extension Tuples
+
+======================================================================*/
+
+#define CISTPL_FUNCE_SERIAL_IF         0x00
+#define CISTPL_FUNCE_SERIAL_CAP                0x01
+#define CISTPL_FUNCE_SERIAL_SERV_DATA  0x02
+#define CISTPL_FUNCE_SERIAL_SERV_FAX   0x03
+#define CISTPL_FUNCE_SERIAL_SERV_VOICE 0x04
+#define CISTPL_FUNCE_SERIAL_CAP_DATA   0x05
+#define CISTPL_FUNCE_SERIAL_CAP_FAX    0x06
+#define CISTPL_FUNCE_SERIAL_CAP_VOICE  0x07
+#define CISTPL_FUNCE_SERIAL_IF_DATA    0x08
+#define CISTPL_FUNCE_SERIAL_IF_FAX     0x09
+#define CISTPL_FUNCE_SERIAL_IF_VOICE   0x0a
+
+/* UART identification */
+#define CISTPL_SERIAL_UART_8250                0x00
+#define CISTPL_SERIAL_UART_16450       0x01
+#define CISTPL_SERIAL_UART_16550       0x02
+#define CISTPL_SERIAL_UART_8251                0x03
+#define CISTPL_SERIAL_UART_8530                0x04
+#define CISTPL_SERIAL_UART_85230       0x05
+
+/* UART capabilities */
+#define CISTPL_SERIAL_UART_SPACE       0x01
+#define CISTPL_SERIAL_UART_MARK                0x02
+#define CISTPL_SERIAL_UART_ODD         0x04
+#define CISTPL_SERIAL_UART_EVEN                0x08
+#define CISTPL_SERIAL_UART_5BIT                0x01
+#define CISTPL_SERIAL_UART_6BIT                0x02
+#define CISTPL_SERIAL_UART_7BIT                0x04
+#define CISTPL_SERIAL_UART_8BIT                0x08
+#define CISTPL_SERIAL_UART_1STOP       0x10
+#define CISTPL_SERIAL_UART_MSTOP       0x20
+#define CISTPL_SERIAL_UART_2STOP       0x40
+
+typedef struct cistpl_serial_t {
+    u_char     uart_type;
+    u_char     uart_cap_0;
+    u_char     uart_cap_1;
+} cistpl_serial_t;
+
+typedef struct cistpl_modem_cap_t {
+    u_char     flow;
+    u_char     cmd_buf;
+    u_char     rcv_buf_0, rcv_buf_1, rcv_buf_2;
+    u_char     xmit_buf_0, xmit_buf_1, xmit_buf_2;
+} cistpl_modem_cap_t;
+
+#define CISTPL_SERIAL_MOD_103          0x01
+#define CISTPL_SERIAL_MOD_V21          0x02
+#define CISTPL_SERIAL_MOD_V23          0x04
+#define CISTPL_SERIAL_MOD_V22          0x08
+#define CISTPL_SERIAL_MOD_212A         0x10
+#define CISTPL_SERIAL_MOD_V22BIS       0x20
+#define CISTPL_SERIAL_MOD_V26          0x40
+#define CISTPL_SERIAL_MOD_V26BIS       0x80
+#define CISTPL_SERIAL_MOD_V27BIS       0x01
+#define CISTPL_SERIAL_MOD_V29          0x02
+#define CISTPL_SERIAL_MOD_V32          0x04
+#define CISTPL_SERIAL_MOD_V32BIS       0x08
+#define CISTPL_SERIAL_MOD_V34          0x10
+
+#define CISTPL_SERIAL_ERR_MNP2_4       0x01
+#define CISTPL_SERIAL_ERR_V42_LAPM     0x02
+
+#define CISTPL_SERIAL_CMPR_V42BIS      0x01
+#define CISTPL_SERIAL_CMPR_MNP5                0x02
+
+#define CISTPL_SERIAL_CMD_AT1          0x01
+#define CISTPL_SERIAL_CMD_AT2          0x02
+#define CISTPL_SERIAL_CMD_AT3          0x04
+#define CISTPL_SERIAL_CMD_MNP_AT       0x08
+#define CISTPL_SERIAL_CMD_V25BIS       0x10
+#define CISTPL_SERIAL_CMD_V25A         0x20
+#define CISTPL_SERIAL_CMD_DMCL         0x40
+
+typedef struct cistpl_data_serv_t {
+    u_char     max_data_0;
+    u_char     max_data_1;
+    u_char     modulation_0;
+    u_char     modulation_1;
+    u_char     error_control;
+    u_char     compression;
+    u_char     cmd_protocol;
+    u_char     escape;
+    u_char     encrypt;
+    u_char     misc_features;
+    u_char     ccitt_code[0];
+} cistpl_data_serv_t;
+
+typedef struct cistpl_fax_serv_t {
+    u_char     max_data_0;
+    u_char     max_data_1;
+    u_char     modulation;
+    u_char     encrypt;
+    u_char     features_0;
+    u_char     features_1;
+    u_char     ccitt_code[0];
+} cistpl_fax_serv_t;
+
+typedef struct cistpl_voice_serv_t {
+    u_char     max_data_0;
+    u_char     max_data_1;
+} cistpl_voice_serv_t;
+
+/*======================================================================
+
+    LAN Function Extension Tuples
+
+======================================================================*/
+
+#define CISTPL_FUNCE_LAN_TECH          0x01
+#define CISTPL_FUNCE_LAN_SPEED         0x02
+#define CISTPL_FUNCE_LAN_MEDIA         0x03
+#define CISTPL_FUNCE_LAN_NODE_ID       0x04
+#define CISTPL_FUNCE_LAN_CONNECTOR     0x05
+
+/* LAN technologies */
+#define CISTPL_LAN_TECH_ARCNET         0x01
+#define CISTPL_LAN_TECH_ETHERNET       0x02
+#define CISTPL_LAN_TECH_TOKENRING      0x03
+#define CISTPL_LAN_TECH_LOCALTALK      0x04
+#define CISTPL_LAN_TECH_FDDI           0x05
+#define CISTPL_LAN_TECH_ATM            0x06
+#define CISTPL_LAN_TECH_WIRELESS       0x07
+
+typedef struct cistpl_lan_tech_t {
+    u_char     tech;
+} cistpl_lan_tech_t;
+
+typedef struct cistpl_lan_speed_t {
+    u_int      speed;
+} cistpl_lan_speed_t;
+
+/* LAN media definitions */
+#define CISTPL_LAN_MEDIA_UTP           0x01
+#define CISTPL_LAN_MEDIA_STP           0x02
+#define CISTPL_LAN_MEDIA_THIN_COAX     0x03
+#define CISTPL_LAN_MEDIA_THICK_COAX    0x04
+#define CISTPL_LAN_MEDIA_FIBER         0x05
+#define CISTPL_LAN_MEDIA_900MHZ                0x06
+#define CISTPL_LAN_MEDIA_2GHZ          0x07
+#define CISTPL_LAN_MEDIA_5GHZ          0x08
+#define CISTPL_LAN_MEDIA_DIFF_IR       0x09
+#define CISTPL_LAN_MEDIA_PTP_IR                0x0a
+
+typedef struct cistpl_lan_media_t {
+    u_char     media;
+} cistpl_lan_media_t;
+
+typedef struct cistpl_lan_node_id_t {
+    u_char     nb;
+    u_char     id[16];
+} cistpl_lan_node_id_t;
+
+typedef struct cistpl_lan_connector_t {
+    u_char     code;
+} cistpl_lan_connector_t;
+
+/*======================================================================
+
+    IDE Function Extension Tuples
+
+======================================================================*/
+
+#define CISTPL_IDE_INTERFACE           0x01
+
+typedef struct cistpl_ide_interface_t {
+    u_char     interface;
+} cistpl_ide_interface_t;
+
+/* First feature byte */
+#define CISTPL_IDE_SILICON             0x04
+#define CISTPL_IDE_UNIQUE              0x08
+#define CISTPL_IDE_DUAL                        0x10
+
+/* Second feature byte */
+#define CISTPL_IDE_HAS_SLEEP           0x01
+#define CISTPL_IDE_HAS_STANDBY         0x02
+#define CISTPL_IDE_HAS_IDLE            0x04
+#define CISTPL_IDE_LOW_POWER           0x08
+#define CISTPL_IDE_REG_INHIBIT         0x10
+#define CISTPL_IDE_HAS_INDEX           0x20
+#define CISTPL_IDE_IOIS16              0x40
+
+typedef struct cistpl_ide_feature_t {
+    u_char     feature1;
+    u_char     feature2;
+} cistpl_ide_feature_t;
+
+#define CISTPL_FUNCE_IDE_IFACE         0x01
+#define CISTPL_FUNCE_IDE_MASTER                0x02
+#define CISTPL_FUNCE_IDE_SLAVE         0x03
+
+/*======================================================================
+
+    Configuration Table Entries
+
+======================================================================*/
+
+#define CISTPL_BAR_SPACE       0x07
+#define CISTPL_BAR_SPACE_IO    0x10
+#define CISTPL_BAR_PREFETCH    0x20
+#define CISTPL_BAR_CACHEABLE   0x40
+#define CISTPL_BAR_1MEG_MAP    0x80
+
+typedef struct cistpl_bar_t {
+    u_char     attr;
+    u_int      size;
+} cistpl_bar_t;
+
+typedef struct cistpl_config_t {
+    u_char     last_idx;
+    u_int      base;
+    u_int      rmask[4];
+    u_char     subtuples;
+} cistpl_config_t;
+
+/* These are bits in the 'present' field, and indices in 'param' */
+#define CISTPL_POWER_VNOM      0
+#define CISTPL_POWER_VMIN      1
+#define CISTPL_POWER_VMAX      2
+#define CISTPL_POWER_ISTATIC   3
+#define CISTPL_POWER_IAVG      4
+#define CISTPL_POWER_IPEAK     5
+#define CISTPL_POWER_IDOWN     6
+
+#define CISTPL_POWER_HIGHZ_OK  0x01
+#define CISTPL_POWER_HIGHZ_REQ 0x02
+
+typedef struct cistpl_power_t {
+    u_char     present;
+    u_char     flags;
+    u_int      param[7];
+} cistpl_power_t;
+
+typedef struct cistpl_timing_t {
+    u_int      wait, waitscale;
+    u_int      ready, rdyscale;
+    u_int      reserved, rsvscale;
+} cistpl_timing_t;
+
+#define CISTPL_IO_LINES_MASK   0x1f
+#define CISTPL_IO_8BIT         0x20
+#define CISTPL_IO_16BIT                0x40
+#define CISTPL_IO_RANGE                0x80
+
+#define CISTPL_IO_MAX_WIN      16
+
+typedef struct cistpl_io_t {
+    u_char     flags;
+    u_char     nwin;
+    struct {
+       u_int   base;
+       u_int   len;
+    } win[CISTPL_IO_MAX_WIN];
+} cistpl_io_t;
+
+typedef struct cistpl_irq_t {
+    u_int      IRQInfo1;
+    u_int      IRQInfo2;
+} cistpl_irq_t;
+
+#define CISTPL_MEM_MAX_WIN     8
+
+typedef struct cistpl_mem_t {
+    u_char     flags;
+    u_char     nwin;
+    struct {
+       u_int   len;
+       u_int   card_addr;
+       u_int   host_addr;
+    } win[CISTPL_MEM_MAX_WIN];
+} cistpl_mem_t;
+
+#define CISTPL_CFTABLE_DEFAULT         0x0001
+#define CISTPL_CFTABLE_BVDS            0x0002
+#define CISTPL_CFTABLE_WP              0x0004
+#define CISTPL_CFTABLE_RDYBSY          0x0008
+#define CISTPL_CFTABLE_MWAIT           0x0010
+#define CISTPL_CFTABLE_AUDIO           0x0800
+#define CISTPL_CFTABLE_READONLY                0x1000
+#define CISTPL_CFTABLE_PWRDOWN         0x2000
+
+typedef struct cistpl_cftable_entry_t {
+    u_char             index;
+    u_short            flags;
+    u_char             interface;
+    cistpl_power_t     vcc, vpp1, vpp2;
+    cistpl_timing_t    timing;
+    cistpl_io_t                io;
+    cistpl_irq_t       irq;
+    cistpl_mem_t       mem;
+    u_char             subtuples;
+} cistpl_cftable_entry_t;
+
+#define CISTPL_CFTABLE_MASTER          0x000100
+#define CISTPL_CFTABLE_INVALIDATE      0x000200
+#define CISTPL_CFTABLE_VGA_PALETTE     0x000400
+#define CISTPL_CFTABLE_PARITY          0x000800
+#define CISTPL_CFTABLE_WAIT            0x001000
+#define CISTPL_CFTABLE_SERR            0x002000
+#define CISTPL_CFTABLE_FAST_BACK       0x004000
+#define CISTPL_CFTABLE_BINARY_AUDIO    0x010000
+#define CISTPL_CFTABLE_PWM_AUDIO       0x020000
+
+typedef struct cistpl_cftable_entry_cb_t {
+    u_char             index;
+    u_int              flags;
+    cistpl_power_t     vcc, vpp1, vpp2;
+    u_char             io;
+    cistpl_irq_t       irq;
+    u_char             mem;
+    u_char             subtuples;
+} cistpl_cftable_entry_cb_t;
+
+typedef struct cistpl_device_geo_t {
+    u_char             ngeo;
+    struct {
+       u_char          buswidth;
+       u_int           erase_block;
+       u_int           read_block;
+       u_int           write_block;
+       u_int           partition;
+       u_int           interleave;
+    } geo[CISTPL_MAX_DEVICES];
+} cistpl_device_geo_t;
+
+typedef struct cistpl_vers_2_t {
+    u_char     vers;
+    u_char     comply;
+    u_short    dindex;
+    u_char     vspec8, vspec9;
+    u_char     nhdr;
+    u_char     vendor, info;
+    char       str[244];
+} cistpl_vers_2_t;
+
+typedef struct cistpl_org_t {
+    u_char     data_org;
+    char       desc[30];
+} cistpl_org_t;
+
+#define CISTPL_ORG_FS          0x00
+#define CISTPL_ORG_APPSPEC     0x01
+#define CISTPL_ORG_XIP         0x02
+
+typedef union cisparse_t {
+    cistpl_device_t            device;
+    cistpl_checksum_t          checksum;
+    cistpl_longlink_t          longlink;
+    cistpl_longlink_mfc_t      longlink_mfc;
+    cistpl_vers_1_t            version_1;
+    cistpl_altstr_t            altstr;
+    cistpl_jedec_t             jedec;
+    cistpl_manfid_t            manfid;
+    cistpl_funcid_t            funcid;
+    cistpl_funce_t             funce;
+    cistpl_bar_t               bar;
+    cistpl_config_t            config;
+    cistpl_cftable_entry_t     cftable_entry;
+    cistpl_cftable_entry_cb_t  cftable_entry_cb;
+    cistpl_device_geo_t                device_geo;
+    cistpl_vers_2_t            vers_2;
+    cistpl_org_t               org;
+} cisparse_t;
+
+typedef struct tuple_t {
+    u_int      Attributes;
+    cisdata_t  DesiredTuple;
+    u_int      Flags;          /* internal use */
+    u_int      LinkOffset;     /* internal use */
+    u_int      CISOffset;      /* internal use */
+    cisdata_t  TupleCode;
+    cisdata_t  TupleLink;
+    cisdata_t  TupleOffset;
+    cisdata_t  TupleDataMax;
+    cisdata_t  TupleDataLen;
+    cisdata_t  *TupleData;
+} tuple_t;
+
+/* Special cisdata_t value */
+#define RETURN_FIRST_TUPLE     0xff
+
+/* Attributes for tuple calls */
+#define TUPLE_RETURN_LINK      0x01
+#define TUPLE_RETURN_COMMON    0x02
+
+/* For ValidateCIS */
+typedef struct cisinfo_t {
+    u_int      Chains;
+} cisinfo_t;
+
+#define CISTPL_MAX_CIS_SIZE    0x200
+
+/* For ReplaceCIS */
+typedef struct cisdump_t {
+    u_int      Length;
+    cisdata_t  Data[CISTPL_MAX_CIS_SIZE];
+} cisdump_t;
+
+#endif /* LINUX_CISTPL_H */
diff --git a/include/pcmcia/cs.h b/include/pcmcia/cs.h
new file mode 100644 (file)
index 0000000..e44e4d8
--- /dev/null
@@ -0,0 +1,467 @@
+/*
+ * cs.h 1.66 1999/08/28 04:12:32
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_CS_H
+#define _LINUX_CS_H
+
+/* For AccessConfigurationRegister */
+typedef struct conf_reg_t {
+    u_char     Function;
+    u_int      Action;
+    off_t      Offset;
+    u_int      Value;
+} conf_reg_t;
+
+/* Actions */
+#define CS_READ                1
+#define CS_WRITE       2
+
+/* for AdjustResourceInfo */
+typedef struct adjust_t {
+    u_int      Action;
+    u_int      Resource;
+    u_int      Attributes;
+    union {
+       struct memory {
+           u_long      Base;
+           u_long      Size;
+       } memory;
+       struct io {
+           ioaddr_t    BasePort;
+           ioaddr_t    NumPorts;
+           u_int       IOAddrLines;
+       } io;
+       struct irq {
+           u_int       IRQ;
+       } irq;
+    } resource;
+} adjust_t;
+
+/* Action field */
+#define REMOVE_MANAGED_RESOURCE                1
+#define ADD_MANAGED_RESOURCE           2
+#define GET_FIRST_MANAGED_RESOURCE     3
+#define GET_NEXT_MANAGED_RESOURCE      4
+/* Resource field */
+#define RES_MEMORY_RANGE               1
+#define RES_IO_RANGE                   2
+#define RES_IRQ                                3
+/* Attribute field */
+#define RES_IRQ_TYPE                   0x03
+#define RES_IRQ_TYPE_EXCLUSIVE         0
+#define RES_IRQ_TYPE_TIME              1
+#define RES_IRQ_TYPE_DYNAMIC           2
+#define RES_IRQ_CSC                    0x04
+#define RES_SHARED                     0x08
+#define RES_RESERVED                   0x10
+#define RES_ALLOCATED                  0x20
+#define RES_REMOVED                    0x40
+
+typedef struct servinfo_t {
+    char       Signature[2];
+    u_int      Count;
+    u_int      Revision;
+    u_int      CSLevel;
+    char       *VendorString;
+} servinfo_t;
+
+typedef struct event_callback_args_t {
+    client_handle_t client_handle;
+    void       *info;
+    void       *mtdrequest;
+    void       *buffer;
+    void       *misc;
+    void       *client_data;
+    struct bus_operations *bus;
+} event_callback_args_t;
+
+/* for GetConfigurationInfo */
+typedef struct config_info_t {
+    u_char     Function;
+    u_int      Attributes;
+    u_int      Vcc, Vpp1, Vpp2;
+    u_int      IntType;
+    u_int      ConfigBase;
+    u_char     Status, Pin, Copy, Option, ExtStatus;
+    u_int      Present;
+    u_int      CardValues;
+    u_int      AssignedIRQ;
+    u_int      IRQAttributes;
+    ioaddr_t   BasePort1;
+    ioaddr_t   NumPorts1;
+    u_int      Attributes1;
+    ioaddr_t   BasePort2;
+    ioaddr_t   NumPorts2;
+    u_int      Attributes2;
+    u_int      IOAddrLines;
+} config_info_t;
+
+/* For CardValues field */
+#define CV_OPTION_VALUE                0x01
+#define CV_STATUS_VALUE                0x02
+#define CV_PIN_REPLACEMENT     0x04
+#define CV_COPY_VALUE          0x08
+#define CV_EXT_STATUS          0x10
+
+/* For GetFirst/NextClient */
+typedef struct client_req_t {
+    socket_t   Socket;
+    u_int      Attributes;
+} client_req_t;
+
+#define CLIENT_THIS_SOCKET     0x01
+
+/* For RegisterClient */
+typedef struct client_reg_t {
+    dev_info_t *dev_info;
+    u_int      Attributes;
+    u_int      EventMask;
+    int                (*event_handler)(event_t event, int priority,
+                                event_callback_args_t *);
+    event_callback_args_t event_callback_args;
+    u_int      Version;
+} client_reg_t;
+
+/* ModifyConfiguration */
+typedef struct modconf_t {
+    u_int      Attributes;
+    u_int      Vcc, Vpp1, Vpp2;
+} modconf_t;
+
+/* Attributes for ModifyConfiguration */
+#define CONF_IRQ_CHANGE_VALID  0x100
+#define CONF_VCC_CHANGE_VALID  0x200
+#define CONF_VPP1_CHANGE_VALID 0x400
+#define CONF_VPP2_CHANGE_VALID 0x800
+
+/* For RequestConfiguration */
+typedef struct config_req_t {
+    u_int      Attributes;
+    u_int      Vcc, Vpp1, Vpp2;
+    u_int      IntType;
+    u_int      ConfigBase;
+    u_char     Status, Pin, Copy, ExtStatus;
+    u_char     ConfigIndex;
+    u_int      Present;
+} config_req_t;
+
+/* Attributes for RequestConfiguration */
+#define CONF_ENABLE_IRQ                0x01
+#define CONF_ENABLE_DMA                0x02
+#define CONF_ENABLE_SPKR       0x04
+#define CONF_VALID_CLIENT      0x100
+
+/* IntType field */
+#define INT_MEMORY             0x01
+#define INT_MEMORY_AND_IO      0x02
+#define INT_CARDBUS            0x04
+
+/* For RequestIO and ReleaseIO */
+typedef struct io_req_t {
+    ioaddr_t   BasePort1;
+    ioaddr_t   NumPorts1;
+    u_int      Attributes1;
+    ioaddr_t   BasePort2;
+    ioaddr_t   NumPorts2;
+    u_int      Attributes2;
+    u_int      IOAddrLines;
+} io_req_t;
+
+/* Attributes for RequestIO and ReleaseIO */
+#define IO_SHARED              0x01
+#define IO_FIRST_SHARED                0x02
+#define IO_FORCE_ALIAS_ACCESS  0x04
+#define IO_DATA_PATH_WIDTH     0x18
+#define IO_DATA_PATH_WIDTH_8   0x00
+#define IO_DATA_PATH_WIDTH_16  0x08
+#define IO_DATA_PATH_WIDTH_AUTO        0x10
+
+/* For RequestIRQ and ReleaseIRQ */
+typedef struct irq_req_t {
+    u_int      Attributes;
+    u_int      AssignedIRQ;
+    u_int      IRQInfo1, IRQInfo2;
+    void       *Handler;
+    void       *Instance;
+} irq_req_t;
+
+/* Attributes for RequestIRQ and ReleaseIRQ */
+#define IRQ_TYPE                       0x03
+#define IRQ_TYPE_EXCLUSIVE             0x00
+#define IRQ_TYPE_TIME                  0x01
+#define IRQ_TYPE_DYNAMIC_SHARING       0x02
+#define IRQ_FORCED_PULSE               0x04
+#define IRQ_FIRST_SHARED               0x08
+#define IRQ_HANDLE_PRESENT             0x10
+#define IRQ_PULSE_ALLOCATED            0x100
+
+/* Bits in IRQInfo1 field */
+#define IRQ_MASK               0x0f
+#define IRQ_NMI_ID             0x01
+#define IRQ_IOCK_ID            0x02
+#define IRQ_BERR_ID            0x04
+#define IRQ_VEND_ID            0x08
+#define IRQ_INFO2_VALID                0x10
+#define IRQ_LEVEL_ID           0x20
+#define IRQ_PULSE_ID           0x40
+#define IRQ_SHARE_ID           0x80
+
+typedef struct eventmask_t {
+    u_int      Attributes;
+    u_int      EventMask;
+} eventmask_t;
+
+#define CONF_EVENT_MASK_VALID  0x01
+
+/* Configuration registers present */
+#define PRESENT_OPTION         0x001
+#define PRESENT_STATUS         0x002
+#define PRESENT_PIN_REPLACE    0x004
+#define PRESENT_COPY           0x008
+#define PRESENT_EXT_STATUS     0x010
+#define PRESENT_IOBASE_0       0x020
+#define PRESENT_IOBASE_1       0x040
+#define PRESENT_IOBASE_2       0x080
+#define PRESENT_IOBASE_3       0x100
+#define PRESENT_IOSIZE         0x200
+
+/* Attributes for Request/GetConfiguration */
+#define CONF_ENABLE_IRQ                0x01
+#define EXCLUSIVE_USE          0x02
+#define VALID_CLIENT           0x04
+
+/* For MapMemPage */
+typedef struct memreq_t {
+    u_int      CardOffset;
+    page_t     Page;
+} memreq_t;
+
+/* For ModifyWindow */
+typedef struct modwin_t {
+    u_int      Attributes;
+    u_int      AccessSpeed;
+} modwin_t;
+
+/* For RequestWindow */
+typedef struct win_req_t {
+    u_int      Attributes;
+    u_long     Base;
+    u_int      Size;
+    u_int      AccessSpeed;
+} win_req_t;
+
+/* Attributes for RequestWindow */
+#define WIN_ADDR_SPACE         0x0001
+#define WIN_ADDR_SPACE_MEM     0x0000
+#define WIN_ADDR_SPACE_IO      0x0001
+#define WIN_MEMORY_TYPE                0x0002
+#define WIN_MEMORY_TYPE_CM     0x0000
+#define WIN_MEMORY_TYPE_AM     0x0002
+#define WIN_ENABLE             0x0004
+#define WIN_DATA_WIDTH         0x0018
+#define WIN_DATA_WIDTH_8       0x0000
+#define WIN_DATA_WIDTH_16      0x0008
+#define WIN_DATA_WIDTH_32      0x0010
+#define WIN_PAGED              0x0020
+#define WIN_SHARED             0x0040
+#define WIN_FIRST_SHARED       0x0080
+#define WIN_USE_WAIT           0x0100
+#define WIN_MAP_BELOW_1MB      0x0400
+#define WIN_PREFETCH           0x0800
+#define WIN_CACHEABLE          0x1000
+#define WIN_BAR_MASK           0xe000
+#define WIN_BAR_SHIFT          13
+
+/* Attributes for RegisterClient */
+#define INFO_MASTER_CLIENT     0x01
+#define INFO_IO_CLIENT         0x02
+#define INFO_MTD_CLIENT                0x04
+#define INFO_MEM_CLIENT                0x08
+#define MAX_NUM_CLIENTS                3
+
+#define INFO_CARD_SHARE                0x10
+#define INFO_CARD_EXCL         0x20
+
+typedef struct cs_status_t {
+    u_char     Function;
+    event_t    CardState;
+    event_t    SocketState;
+} cs_status_t;
+
+typedef struct error_info_t {
+    int                func;
+    int                retcode;
+} error_info_t;
+
+/* Special stuff for binding drivers to sockets */
+typedef struct bind_req_t {
+    socket_t   Socket;
+    u_char     Function;
+    dev_info_t *dev_info;
+} bind_req_t;
+
+/* Flag to bind to all functions */
+#define BIND_FN_ALL    0xff
+
+typedef struct mtd_bind_t {
+    socket_t   Socket;
+    u_int      Attributes;
+    u_int      CardOffset;
+    dev_info_t *dev_info;
+} mtd_bind_t;
+
+/* Events */
+#define CS_EVENT_PRI_LOW               0
+#define CS_EVENT_PRI_HIGH              1
+
+#define CS_EVENT_WRITE_PROTECT         0x000001
+#define CS_EVENT_CARD_LOCK             0x000002
+#define CS_EVENT_CARD_INSERTION                0x000004
+#define CS_EVENT_CARD_REMOVAL          0x000008
+#define CS_EVENT_BATTERY_DEAD          0x000010
+#define CS_EVENT_BATTERY_LOW           0x000020
+#define CS_EVENT_READY_CHANGE          0x000040
+#define CS_EVENT_CARD_DETECT           0x000080
+#define CS_EVENT_RESET_REQUEST         0x000100
+#define CS_EVENT_RESET_PHYSICAL                0x000200
+#define CS_EVENT_CARD_RESET            0x000400
+#define CS_EVENT_REGISTRATION_COMPLETE 0x000800
+#define CS_EVENT_RESET_COMPLETE                0x001000
+#define CS_EVENT_PM_SUSPEND            0x002000
+#define CS_EVENT_PM_RESUME             0x004000
+#define CS_EVENT_INSERTION_REQUEST     0x008000
+#define CS_EVENT_EJECTION_REQUEST      0x010000
+#define CS_EVENT_MTD_REQUEST           0x020000
+#define CS_EVENT_ERASE_COMPLETE                0x040000
+#define CS_EVENT_REQUEST_ATTENTION     0x080000
+#define CS_EVENT_CB_DETECT             0x100000
+#define CS_EVENT_3VCARD                        0x200000
+#define CS_EVENT_XVCARD                        0x400000
+
+/* Return codes */
+#define CS_SUCCESS             0x00
+#define CS_BAD_ADAPTER         0x01
+#define CS_BAD_ATTRIBUTE       0x02
+#define CS_BAD_BASE            0x03
+#define CS_BAD_EDC             0x04
+#define CS_BAD_IRQ             0x06
+#define CS_BAD_OFFSET          0x07
+#define CS_BAD_PAGE            0x08
+#define CS_READ_FAILURE                0x09
+#define CS_BAD_SIZE            0x0a
+#define CS_BAD_SOCKET          0x0b
+#define CS_BAD_TYPE            0x0d
+#define CS_BAD_VCC             0x0e
+#define CS_BAD_VPP             0x0f
+#define CS_BAD_WINDOW          0x11
+#define CS_WRITE_FAILURE       0x12
+#define CS_NO_CARD             0x14
+#define CS_UNSUPPORTED_FUNCTION        0x15
+#define CS_UNSUPPORTED_MODE    0x16
+#define CS_BAD_SPEED           0x17
+#define CS_BUSY                        0x18
+#define CS_GENERAL_FAILURE     0x19
+#define CS_WRITE_PROTECTED     0x1a
+#define CS_BAD_ARG_LENGTH      0x1b
+#define CS_BAD_ARGS            0x1c
+#define CS_CONFIGURATION_LOCKED        0x1d
+#define CS_IN_USE              0x1e
+#define CS_NO_MORE_ITEMS       0x1f
+#define CS_OUT_OF_RESOURCE     0x20
+#define CS_BAD_HANDLE          0x21
+
+#define CS_BAD_TUPLE           0x40
+
+#ifdef __KERNEL__
+
+/*
+ *  Calls to set up low-level "Socket Services" drivers
+ */
+
+typedef int (*ss_entry_t)(u_int sock, u_int cmd, void *arg);
+extern int register_ss_entry(int nsock, ss_entry_t entry);
+extern void unregister_ss_entry(ss_entry_t entry);
+
+/*
+ *  The main Card Services entry point
+ */
+
+enum service {
+    AccessConfigurationRegister, AddSocketServices,
+    AdjustResourceInfo, CheckEraseQueue, CloseMemory, CopyMemory,
+    DeregisterClient, DeregisterEraseQueue, GetCardServicesInfo,
+    GetClientInfo, GetConfigurationInfo, GetEventMask,
+    GetFirstClient, GetFirstPartion, GetFirstRegion, GetFirstTuple,
+    GetNextClient, GetNextPartition, GetNextRegion, GetNextTuple,
+    GetStatus, GetTupleData, MapLogSocket, MapLogWindow, MapMemPage,
+    MapPhySocket, MapPhyWindow, ModifyConfiguration, ModifyWindow,
+    OpenMemory, ParseTuple, ReadMemory, RegisterClient,
+    RegisterEraseQueue, RegisterMTD, RegisterTimer,
+    ReleaseConfiguration, ReleaseExclusive, ReleaseIO, ReleaseIRQ,
+    ReleaseSocketMask, ReleaseWindow, ReplaceSocketServices,
+    RequestConfiguration, RequestExclusive, RequestIO, RequestIRQ,
+    RequestSocketMask, RequestWindow, ResetCard, ReturnSSEntry,
+    SetEventMask, SetRegion, ValidateCIS, VendorSpecific,
+    WriteMemory, BindDevice, BindMTD, ReportError,
+    SuspendCard, ResumeCard, EjectCard, InsertCard, ReplaceCIS
+};
+
+#ifdef IN_CARD_SERVICES
+extern int CardServices(int func, void *a1, void *a2, void *a3);
+#else
+extern int CardServices(int func, ...);
+#endif
+
+#ifdef __BEOS__
+#define SS_MODULE_NAME(s)      ("busses/pcmcia/" s "/v1")
+#define MTD_MODULE_NAME(s)     ("busses/pcmcia/" s "/v1")
+#define CS_CLIENT_MODULE_NAME  "bus_managers/pcmcia_cs/client/v1"
+typedef struct cs_client_module_info {
+    bus_manager_info   binfo;
+    int (*_CardServices)(int, ...);
+    int (*_MTDHelperEntry)(int, ...);
+    void (*_add_timer)(struct timer_list *);
+    void (*_del_timer)(struct timer_list *);
+} cs_client_module_info;
+#define CS_SOCKET_MODULE_NAME "bus_managers/pcmcia_cs/socket/v1"
+typedef struct cs_socket_module_info {
+    bus_manager_info   binfo;
+    int (*_register_ss_entry)(int, ss_entry_t);
+    void (*_unregister_ss_entry)(ss_entry_t);
+    void (*_add_timer)(struct timer_list *);
+    void (*_del_timer)(struct timer_list *);
+    int (*register_resource)(int, u_long, u_long);
+    int (*release_resource)(int, u_long, u_long);
+    int (*check_resource)(int, u_long, u_long);
+} cs_socket_module_info;
+#endif
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_CS_H */
diff --git a/include/pcmcia/cs_types.h b/include/pcmcia/cs_types.h
new file mode 100644 (file)
index 0000000..3df641d
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * cs_types.h 1.15 1999/08/28 04:12:32
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_CS_TYPES_H
+#define _LINUX_CS_TYPES_H
+
+#ifdef __linux__
+#include <linux/types.h>
+#endif
+
+typedef u_short        socket_t;
+typedef u_short        ioaddr_t;
+typedef u_int  event_t;
+typedef u_char cisdata_t;
+typedef u_short        page_t;
+
+struct client_t;
+typedef struct client_t *client_handle_t;
+
+struct window_t;
+typedef struct window_t *window_handle_t;
+
+struct region_t;
+typedef struct region_t *memory_handle_t;
+
+struct eraseq_t;
+typedef struct eraseq_t *eraseq_handle_t;
+
+#ifndef DEV_NAME_LEN
+#define DEV_NAME_LEN 32
+#endif
+
+typedef char dev_info_t[DEV_NAME_LEN];
+
+#endif /* _LINUX_CS_TYPES_H */
diff --git a/include/pcmcia/driver_ops.h b/include/pcmcia/driver_ops.h
new file mode 100644 (file)
index 0000000..395374c
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * driver_ops.h 1.13 1999/08/28 04:12:33
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_DRIVER_OPS_H
+#define _LINUX_DRIVER_OPS_H
+
+#ifndef DEV_NAME_LEN
+#define DEV_NAME_LEN   32
+#endif
+
+#ifdef __KERNEL__
+
+typedef struct dev_node_t {
+    char               dev_name[DEV_NAME_LEN];
+    u_short            major, minor;
+    struct dev_node_t  *next;
+} dev_node_t;
+
+typedef struct dev_locator_t {
+    enum { LOC_ISA, LOC_PCI } bus;
+    union {
+       struct {
+           u_short     io_base_1, io_base_2;
+           u_long      mem_base;
+           u_char      irq, dma;
+       } isa;
+       struct {
+           u_char      bus;
+           u_char      devfn;
+       } pci;
+    } b;
+} dev_locator_t;
+
+typedef struct driver_operations {
+    char               *name;
+    dev_node_t         *(*attach) (dev_locator_t *loc);
+    void               (*suspend) (dev_node_t *dev);
+    void               (*resume) (dev_node_t *dev);
+    void               (*detach) (dev_node_t *dev);
+} driver_operations;
+
+int register_driver(struct driver_operations *ops);
+void unregister_driver(struct driver_operations *ops);
+
+#ifdef __BEOS__
+#define CB_ENABLER_MODULE_NAME "bus_managers/cb_enabler/v1"
+typedef struct cb_enabler_module_info {
+    bus_manager_info   binfo;
+    int (*register_driver)(struct driver_operations *ops);
+    void (*unregister_driver)(struct driver_operations *ops);
+} cb_enabler_module_info;
+#endif /* __BEOS__ */
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_DRIVER_OPS_H */
diff --git a/include/pcmcia/ds.h b/include/pcmcia/ds.h
new file mode 100644 (file)
index 0000000..2eafab2
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * ds.h 1.53 1999/08/28 04:12:33
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_DS_H
+#define _LINUX_DS_H
+
+#include <pcmcia/driver_ops.h>
+#include <pcmcia/bulkmem.h>
+
+typedef struct tuple_parse_t {
+    tuple_t            tuple;
+    cisdata_t          data[255];
+    cisparse_t         parse;
+} tuple_parse_t;
+
+typedef struct bind_info_t {
+    dev_info_t         dev_info;
+    u_char             function;
+    struct dev_link_t  *instance;
+    char               name[DEV_NAME_LEN];
+    u_short            major, minor;
+    void               *next;
+} bind_info_t;
+
+typedef struct mtd_info_t {
+    dev_info_t         dev_info;
+    u_int              Attributes;
+    u_int              CardOffset;
+} mtd_info_t;
+
+typedef union ds_ioctl_arg_t {
+    servinfo_t         servinfo;
+    adjust_t           adjust;
+    config_info_t      config;
+    tuple_t            tuple;
+    tuple_parse_t      tuple_parse;
+    client_req_t       client_req;
+    cs_status_t                status;
+    conf_reg_t         conf_reg;
+    cisinfo_t          cisinfo;
+    region_info_t      region;
+    bind_info_t                bind_info;
+    mtd_info_t         mtd_info;
+    cisdump_t          cisdump;
+} ds_ioctl_arg_t;
+
+#define DS_GET_CARD_SERVICES_INFO      _IOR ('d', 1, servinfo_t)
+#define DS_ADJUST_RESOURCE_INFO                _IOWR('d', 2, adjust_t)
+#define DS_GET_CONFIGURATION_INFO      _IOWR('d', 3, config_info_t)
+#define DS_GET_FIRST_TUPLE             _IOWR('d', 4, tuple_t)
+#define DS_GET_NEXT_TUPLE              _IOWR('d', 5, tuple_t)
+#define DS_GET_TUPLE_DATA              _IOWR('d', 6, tuple_parse_t)
+#define DS_PARSE_TUPLE                 _IOWR('d', 7, tuple_parse_t)
+#define DS_RESET_CARD                  _IO  ('d', 8)
+#define DS_GET_STATUS                  _IOWR('d', 9, cs_status_t)
+#define DS_ACCESS_CONFIGURATION_REGISTER _IOWR('d', 10, conf_reg_t)
+#define DS_VALIDATE_CIS                        _IOR ('d', 11, cisinfo_t)
+#define DS_SUSPEND_CARD                        _IO  ('d', 12)
+#define DS_RESUME_CARD                 _IO  ('d', 13)
+#define DS_EJECT_CARD                  _IO  ('d', 14)
+#define DS_INSERT_CARD                 _IO  ('d', 15)
+#define DS_GET_FIRST_REGION            _IOWR('d', 16, region_info_t)
+#define DS_GET_NEXT_REGION             _IOWR('d', 17, region_info_t)
+#define DS_REPLACE_CIS                 _IOWR('d', 18, cisdump_t)
+
+#define DS_BIND_REQUEST                        _IOWR('d', 60, bind_info_t)
+#define DS_GET_DEVICE_INFO             _IOWR('d', 61, bind_info_t) 
+#define DS_GET_NEXT_DEVICE             _IOWR('d', 62, bind_info_t) 
+#define DS_UNBIND_REQUEST              _IOW ('d', 63, bind_info_t)
+#define DS_BIND_MTD                    _IOWR('d', 64, mtd_info_t)
+
+#ifdef __KERNEL__
+
+typedef struct dev_link_t {
+    dev_node_t         *dev;
+    u_int              state, open;
+    wait_queue_head_t  pending;
+    struct timer_list  release;
+    client_handle_t    handle;
+    io_req_t           io;
+    irq_req_t          irq;
+    config_req_t       conf;
+    window_handle_t    win;
+    void               *priv;
+    struct dev_link_t  *next;
+} dev_link_t;
+
+/* Flags for device state */
+#define DEV_PRESENT            0x01
+#define DEV_CONFIG             0x02
+#define DEV_STALE_CONFIG       0x04    /* release on close */
+#define DEV_STALE_LINK         0x08    /* detach on release */
+#define DEV_CONFIG_PENDING     0x10
+#define DEV_RELEASE_PENDING    0x20
+#define DEV_SUSPEND            0x40
+#define DEV_BUSY               0x80
+
+#define DEV_OK(l) \
+    ((l) && ((l->state & ~DEV_BUSY) == (DEV_CONFIG|DEV_PRESENT)))
+
+int register_pccard_driver(dev_info_t *dev_info,
+                          dev_link_t *(*attach)(void),
+                          void (*detach)(dev_link_t *));
+
+int unregister_pccard_driver(dev_info_t *dev_info);
+
+#define register_pcmcia_driver register_pccard_driver
+#define unregister_pcmcia_driver unregister_pccard_driver
+
+#ifdef __BEOS__
+#define DS_MODULE_NAME "bus_managers/pcmcia_ds/v1"
+typedef struct ds_module_info {
+    bus_manager_info binfo;
+    int (*_register_pccard_driver)(dev_info_t *,
+                                  dev_link_t *(*)(void),
+                                  void (*)(dev_link_t *));
+    int (*_unregister_pccard_driver)(dev_info_t *);
+    struct driver_info_t **root_driver;
+    int *sockets;
+    struct socket_info_t **socket_table;
+    sem_id *list_sem;
+} ds_module_info;
+#endif /* __BEOS__ */
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_DS_H */
diff --git a/include/pcmcia/ftl.h b/include/pcmcia/ftl.h
new file mode 100644 (file)
index 0000000..8bf70a5
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * ftl.h 1.6 1999/08/28 04:12:33
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_FTL_H
+#define _LINUX_FTL_H
+
+typedef struct erase_unit_header_t {
+    u_char     LinkTargetTuple[5];
+    u_char     DataOrgTuple[10];
+    u_char     NumTransferUnits;
+    u_int      EraseCount;
+    u_short    LogicalEUN;
+    u_char     BlockSize;
+    u_char     EraseUnitSize;
+    u_short    FirstPhysicalEUN;
+    u_short    NumEraseUnits;
+    u_int      FormattedSize;
+    u_int      FirstVMAddress;
+    u_short    NumVMPages;
+    u_char     Flags;
+    u_char     Code;
+    u_int      SerialNumber;
+    u_int      AltEUHOffset;
+    u_int      BAMOffset;
+    u_char     Reserved[12];
+    u_char     EndTuple[2];
+} erase_unit_header_t;
+
+/* Flags in erase_unit_header_t */
+#define HIDDEN_AREA            0x01
+#define REVERSE_POLARITY       0x02
+#define DOUBLE_BAI             0x04
+
+/* Definitions for block allocation information */
+
+#define BLOCK_FREE(b)          ((b) == 0xffffffff)
+#define BLOCK_DELETED(b)       (((b) == 0) || ((b) == 0xfffffffe))
+
+#define BLOCK_TYPE(b)          ((b) & 0x7f)
+#define BLOCK_ADDRESS(b)       ((b) & ~0x7f)
+#define BLOCK_NUMBER(b)                ((b) >> 9)
+#define BLOCK_CONTROL          0x30
+#define BLOCK_DATA             0x40
+#define BLOCK_REPLACEMENT      0x60
+#define BLOCK_BAD              0x70
+
+#endif /* _LINUX_FTL_H */
diff --git a/include/pcmcia/mem_op.h b/include/pcmcia/mem_op.h
new file mode 100644 (file)
index 0000000..b13f2a7
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * mem_op.h 1.10 1999/08/28 04:12:33
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_MEM_OP_H
+#define _LINUX_MEM_OP_H
+
+#include <asm/uaccess.h>
+
+/*
+   If UNSAFE_MEMCPY is defined, we use the (optimized) system routines
+   to copy between a card and kernel memory.  These routines do 32-bit
+   operations which may not work with all PCMCIA controllers.  The
+   safe versions defined here will do only 8-bit and 16-bit accesses.
+*/
+
+#ifdef UNSAFE_MEMCPY
+
+#define copy_from_pc memcpy_fromio
+#define copy_to_pc memcpy_toio
+
+static inline void copy_pc_to_user(void *to, const void *from, size_t n)
+{
+    size_t odd = (n & 3);
+    n -= odd;
+    while (n) {
+       put_user(readl_ns(from), (int *)to);
+       (char *)from += 4; (char *)to += 4; n -= 4;
+    }
+    while (odd--)
+       put_user(readb((char *)from++), (char *)to++);
+}
+
+static inline void copy_user_to_pc(void *to, const void *from, size_t n)
+{
+    int l;
+    char c;
+    size_t odd = (n & 3);
+    n -= odd;
+    while (n) {
+       get_user(l, (int *)from);
+       writel_ns(l, to);
+       (char *)to += 4; (char *)from += 4; n -= 4;
+    }
+    while (odd--) {
+       get_user(c, (char *)from++);
+       writeb(c, (char *)to++);
+    }
+}
+
+#else /* UNSAFE_MEMCPY */
+
+static inline void copy_from_pc(void *to, const void *from, size_t n)
+{
+    size_t odd = (n & 1);
+    n -= odd;
+    while (n) {
+       *(u_short *)to = __raw_readw(from);
+       (char *)to += 2; (char *)from += 2; n -= 2;
+    }
+    if (odd)
+       *(u_char *)to = readb(from);
+}
+
+static inline void copy_to_pc(void *to, const void *from, size_t n)
+{
+    size_t odd = (n & 1);
+    n -= odd;
+    while (n) {
+       __raw_writew(*(u_short *)from, to);
+       (char *)to += 2; (char *)from += 2; n -= 2;
+    }
+    if (odd)
+       writeb(*(u_char *)from, to);
+}
+
+static inline void copy_pc_to_user(void *to, const void *from, size_t n)
+{
+    size_t odd = (n & 1);
+    n -= odd;
+    while (n) {
+       put_user(__raw_readw(from), (short *)to);
+       (char *)to += 2; (char *)from += 2; n -= 2;
+    }
+    if (odd)
+       put_user(readb(from), (char *)to);
+}
+
+static inline void copy_user_to_pc(void *to, const void *from, size_t n)
+{
+    short s;
+    char c;
+    size_t odd = (n & 1);
+    n -= odd;
+    while (n) {
+       get_user(s, (short *)from);
+       __raw_writew(s, to);
+       (char *)to += 2; (char *)from += 2; n -= 2;
+    }
+    if (odd) {
+       get_user(c, (char *)from);
+       writeb(c, to);
+    }
+}
+
+#endif /* UNSAFE_MEMCPY */
+
+#endif /* _LINUX_MEM_OP_H */
diff --git a/include/pcmcia/memory.h b/include/pcmcia/memory.h
new file mode 100644 (file)
index 0000000..8324ac4
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * memory.h 1.5 1999/08/28 04:12:33
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_MEMORY_H
+#define _LINUX_MEMORY_H
+
+typedef struct erase_info_t {
+    u_long     Offset;
+    u_long     Size;
+} erase_info_t;
+
+#define MEMGETINFO             _IOR('M', 1, region_info_t)
+#define MEMERASE               _IOW('M', 2, erase_info_t)
+
+#endif /* _LINUX_MEMORY_H */
diff --git a/include/pcmcia/ss.h b/include/pcmcia/ss.h
new file mode 100644 (file)
index 0000000..e39477e
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * ss.h 1.24 1999/08/28 04:12:33
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_SS_H
+#define _LINUX_SS_H
+
+/* For RegisterCallback */
+typedef struct ss_callback_t {
+    void       (*handler)(void *info, u_int events);
+    void       *info;
+} ss_callback_t;
+
+/* Definitions for card status flags for GetStatus */
+#define SS_WRPROT      0x0001
+#define SS_CARDLOCK    0x0002
+#define SS_EJECTION    0x0004
+#define SS_INSERTION   0x0008
+#define SS_BATDEAD     0x0010
+#define SS_BATWARN     0x0020
+#define SS_READY       0x0040
+#define SS_DETECT      0x0080
+#define SS_POWERON     0x0100
+#define SS_GPI         0x0200
+#define SS_STSCHG      0x0400
+#define SS_CARDBUS     0x0800
+#define SS_3VCARD      0x1000
+#define SS_XVCARD      0x2000
+
+/* for InquireSocket */
+typedef struct socket_cap_t {
+    u_int      features;
+    u_int      irq_mask;
+    u_int      map_size;
+    u_char     pci_irq;
+    u_char     cardbus;
+    struct pci_bus *cb_bus;
+    struct bus_operations *bus;
+} socket_cap_t;
+
+/* InquireSocket capabilities */
+#define SS_CAP_PAGE_REGS       0x0001
+#define SS_CAP_VIRTUAL_BUS     0x0002
+#define SS_CAP_MEM_ALIGN       0x0004
+#define SS_CAP_PCCARD          0x4000
+#define SS_CAP_CARDBUS         0x8000
+
+/* for GetSocket, SetSocket */
+typedef struct socket_state_t {
+    u_int      flags;
+    u_int      csc_mask;
+    u_char     Vcc, Vpp;
+    u_char     io_irq;
+} socket_state_t;
+
+/* Socket configuration flags */
+#define SS_PWR_AUTO    0x0010
+#define SS_IOCARD      0x0020
+#define SS_RESET       0x0040
+#define SS_DMA_MODE    0x0080
+#define SS_SPKR_ENA    0x0100
+#define SS_OUTPUT_ENA  0x0200
+
+/* Flags for I/O port and memory windows */
+#define MAP_ACTIVE     0x01
+#define MAP_16BIT      0x02
+#define MAP_AUTOSZ     0x04
+#define MAP_0WS                0x08
+#define MAP_WRPROT     0x10
+#define MAP_ATTRIB     0x20
+#define MAP_USE_WAIT   0x40
+#define MAP_PREFETCH   0x80
+
+/* Use this just for bridge windows */
+#define MAP_IOSPACE    0x20
+
+typedef struct pccard_io_map {
+    u_char     map;
+    u_char     flags;
+    u_short    speed;
+    u_short    start, stop;
+} pccard_io_map;
+
+typedef struct pccard_mem_map {
+    u_char     map;
+    u_char     flags;
+    u_short    speed;
+    u_long     sys_start, sys_stop;
+    u_int      card_start;
+} pccard_mem_map;
+
+typedef struct cb_bridge_map {
+    u_char     map;
+    u_char     flags;
+    u_int      start, stop;
+} cb_bridge_map;
+
+enum ss_service {
+    SS_RegisterCallback, SS_InquireSocket,
+    SS_GetStatus, SS_GetSocket, SS_SetSocket,
+    SS_GetIOMap, SS_SetIOMap, SS_GetMemMap, SS_SetMemMap,
+    SS_GetBridge, SS_SetBridge, SS_ProcSetup
+};
+
+#endif /* _LINUX_SS_H */
diff --git a/include/pcmcia/version.h b/include/pcmcia/version.h
new file mode 100644 (file)
index 0000000..0df81b3
--- /dev/null
@@ -0,0 +1,4 @@
+/* version.h 1.72 1999/08/05 06:09:53 (David Hinds) */
+
+#define CS_RELEASE "3.1.0"
+#define CS_RELEASE_CODE 0x3100
index 2b9e98b2ba61c01c71f46e62c3cbefe0856977cf..571572406cc2a26c95e73a8eb86e716cd4d5acca 100644 (file)
@@ -84,6 +84,7 @@ extern void ppc_init(void);
 extern void sysctl_init(void);
 extern void filescache_init(void);
 extern void signals_init(void);
+extern int pcmcia_init(void);
 
 extern void free_initmem(void);
 extern void filesystem_setup(void);
@@ -657,7 +658,9 @@ static void __init do_basic_setup(void)
 #ifdef CONFIG_IRDA
        irda_device_init(); /* Must be done after protocol initialization */
 #endif
-
+#ifdef CONFIG_PCMCIA
+       pcmcia_init();          /* Do this last */
+#endif
        /* Mount the root filesystem.. */
        mount_root();
 
index e2c7967e87b8404a452270d9cac608f0311593f2..71761a3b1f16f0eeba5de231c0a5b1136207a32b 100644 (file)
@@ -320,6 +320,7 @@ EXPORT_SYMBOL(enable_hlt);
 /* resource handling */
 EXPORT_SYMBOL(request_resource);
 EXPORT_SYMBOL(release_resource);
+EXPORT_SYMBOL(allocate_resource);
 EXPORT_SYMBOL(__request_region);
 EXPORT_SYMBOL(__check_region);
 EXPORT_SYMBOL(__release_region);
index bad408d03e2598f55827cb9e310e8861552a2269..5efa9aaf76386393bf58de18ba91cc80c701f803 100644 (file)
@@ -1303,7 +1303,7 @@ static unsigned long filemap_nopage(struct vm_area_struct * area,
        struct dentry * dentry = file->f_dentry;
        struct inode * inode = dentry->d_inode;
        struct page * page, **hash;
-       unsigned long old_page, new_page = 0;
+       unsigned long old_page;
 
        unsigned long offset = address - area->vm_start + area->vm_offset;
 
@@ -1339,18 +1339,19 @@ success:
         * and possibly copy it over to another page..
         */
        old_page = page_address(page);
-       if (!no_share) {
-               flush_page_to_ram(old_page);
-               return old_page;
-       }
+       if (no_share) {
+               unsigned long new_page = page_cache_alloc();
 
-       new_page = page_cache_alloc();
-       if (new_page) {
-               copy_page(new_page, old_page);
-               flush_page_to_ram(new_page);
+               if (new_page) {
+                       copy_page(new_page, old_page);
+                       flush_page_to_ram(new_page);
+               }
+               page_cache_release(page);
+               return new_page;
        }
-       page_cache_release(page);
-       return new_page;
+               
+       flush_page_to_ram(old_page);
+       return old_page;
 
 no_cached_page:
        /*
@@ -1408,8 +1409,6 @@ page_not_uptodate:
         * mm layer so, possibly freeing the page cache page first.
         */
        page_cache_release(page);
-       if (new_page)
-               page_cache_free(new_page);
        return 0;
 }
 
index c20f85303b8b77dcd8b1e68fd120e904e97fd4da..07970a18e86ba9e860c52ad5ff5fc428fb248b0e 100644 (file)
@@ -27,6 +27,7 @@
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>
 #include <net/checksum.h>
+#include <net/sock.h>
 
 /*
  *     Verify iovec. The caller must ensure that the iovec is big enough
index f9e34e071bfddd58d463e3061a143932c1820476..b459b51fe13bf4b57f559b4e43edf416d05358e7 100644 (file)
@@ -214,9 +214,9 @@ situation, and they don't change anyhow.
 
 */
 
-static char NoPerm[] = "403 Permission denied\r\nServer: kHTTPd 0.1.6\r\n\r\n Permission denied";
-static char TryLater[] = "500 Try again later\r\nServer: kHTTPd 0.1.6\r\n\r\n Try again later";
-static char NotModified[] = "304 Not Modified\r\nServer: kHTTPd 0.1.6\r\n\r\n";
+static char NoPerm[] = "HTTP/1.0 403 Forbidden\r\nServer: kHTTPd 0.1.6\r\n\r\n";
+static char TryLater[] = "HTTP/1.0 503 Service Unavailable\r\nServer: kHTTPd 0.1.6\r\nContent-Length: 15\r\n\r\nTry again later";
+static char NotModified[] = "HTTP/1.0 304 Not Modified\r\nServer: kHTTPd 0.1.6\r\n\r\n";
 
 
 void Send403(struct socket *sock)
@@ -229,7 +229,7 @@ void Send403(struct socket *sock)
 void Send304(struct socket *sock)
 {
        EnterFunction("Send304");
-       (void)SendBuffer(sock,NotModified,strlen(NoPerm));
+       (void)SendBuffer(sock,NotModified,strlen(NotModified));
        LeaveFunction("Send304");
 }